[
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Israel Lot\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and 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 included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "#  copyright (c) 2010 Espressif System\n#\nifndef PDIR\n\nendif\n\n# Base directory for the compiler\nXTENSA_TOOLS_ROOT ?= /opt/xtensa-lx106-elf/bin\n\n#############################################################\n# Select compile\n#\nifeq ($(OS),Windows_NT)\n# WIN32\n# We are under windows.\n\tifeq ($(XTENSA_CORE),lx106)\n\t\t# It is xcc\n\t\tAR = xt-ar\n\t\tCC = xt-xcc\n\t\tNM = xt-nm\n\t\tCPP = xt-cpp\n\t\tOBJCOPY = xt-objcopy\n\t\t#MAKE = xt-make\n\t\tCCFLAGS += -Os --rename-section .text=.irom0.text --rename-section .literal=.irom0.literal\n\telse \n\t\t# It is gcc, may be cygwin\n\t\t# Can we use -fdata-sections?\n\t\tCCFLAGS += -Os -ffunction-sections -fno-jump-tables \n\t\tAR = xtensa-lx106-elf-ar\n\t\tCC = xtensa-lx106-elf-gcc\n\t\tNM = xtensa-lx106-elf-nm\n\t\tCPP = xtensa-lx106-elf-cpp\n\t\tOBJCOPY = xtensa-lx106-elf-objcopy\n\tendif\n\tFIRMWAREDIR = ..\\\\bin\\\\\n\tifndef COMPORT\n\t\tESPPORT = com1\n\telse\n\t\tESPPORT = $(COMPORT)\n\tendif\n    ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)\n# ->AMD64\n    endif\n    ifeq ($(PROCESSOR_ARCHITECTURE),x86)\n# ->IA32\n    endif\nelse\n# We are under other system, may be Linux. Assume using gcc.\n\t# Can we use -fdata-sections?\n\tifndef COMPORT\n\t\tESPPORT = /dev/ttyUSB0\n\telse\n\t\tESPPORT = $(COMPORT)\n\tendif\n\tCCFLAGS += -Os -ffunction-sections -fno-jump-tables \n\tAR = xtensa-lx106-elf-ar\n\tCC = xtensa-lx106-elf-gcc\n\tNM = xtensa-lx106-elf-nm\n\tCPP = xtensa-lx106-elf-cpp\n\tOBJCOPY = xtensa-lx106-elf-objcopy\n\tFIRMWAREDIR = ../bin/\n    UNAME_S := $(shell uname -s)\n    ifeq ($(UNAME_S),Linux)\n# LINUX\n    endif\n    ifeq ($(UNAME_S),Darwin)\n# OSX\n    endif\n    UNAME_P := $(shell uname -p)\n    ifeq ($(UNAME_P),x86_64)\n# ->AMD64\n    endif\n    ifneq ($(filter %86,$(UNAME_P)),)\n# ->IA32\n    endif\n    ifneq ($(filter arm%,$(UNAME_P)),)\n# ->ARM\n    endif\nendif\n#############################################################\nESPTOOL ?= ../tools/esptool.py\nMKFSTOOL ?= tools/mkfs.py\n\n\nCSRCS ?= $(wildcard *.c)\nASRCs ?= $(wildcard *.s)\nASRCS ?= $(wildcard *.S)\nSUBDIRS ?= $(patsubst %/,%,$(dir $(wildcard */Makefile)))\n\nODIR := .output\nOBJODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/obj\n\nOBJS := $(CSRCS:%.c=$(OBJODIR)/%.o) \\\n        $(ASRCs:%.s=$(OBJODIR)/%.o) \\\n        $(ASRCS:%.S=$(OBJODIR)/%.o)\n\nDEPS := $(CSRCS:%.c=$(OBJODIR)/%.d) \\\n        $(ASRCs:%.s=$(OBJODIR)/%.d) \\\n        $(ASRCS:%.S=$(OBJODIR)/%.d)\n\nLIBODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/lib\nOLIBS := $(GEN_LIBS:%=$(LIBODIR)/%)\n\nIMAGEODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/image\nOIMAGES := $(GEN_IMAGES:%=$(IMAGEODIR)/%)\n\nBINODIR := $(ODIR)/$(TARGET)/$(FLAVOR)/bin\nOBINS := $(GEN_BINS:%=$(BINODIR)/%)\n\nCCFLAGS += \t\t\t\\\n\t-g\t\t\t\\\n\t-O2\t\t\t\\\n\t-Wpointer-arith\t\t\\\n\t-Wundef\t\t\t\\\n\t-Werror\t\t\t\\\n\t-Wl,-EL\t\t\t\\\n\t-fno-inline-functions\t\\\n\t-nostdlib       \\\n\t-mlongcalls\t\\\n\t-mtext-section-literals \\\n#\t-Wall\t\t\t\n\nCFLAGS = $(CCFLAGS) $(DEFINES) $(EXTRA_CCFLAGS) $(INCLUDES)\nDFLAGS = $(CCFLAGS) $(DDEFINES) $(EXTRA_CCFLAGS) $(INCLUDES)\n\n\n#############################################################\n# Functions\n#\n\ndefine ShortcutRule\n$(1): .subdirs $(2)/$(1)\nendef\n\ndefine MakeLibrary\nDEP_LIBS_$(1) = $$(foreach lib,$$(filter %.a,$$(COMPONENTS_$(1))),$$(dir $$(lib))$$(LIBODIR)/$$(notdir $$(lib)))\nDEP_OBJS_$(1) = $$(foreach obj,$$(filter %.o,$$(COMPONENTS_$(1))),$$(dir $$(obj))$$(OBJODIR)/$$(notdir $$(obj)))\n$$(LIBODIR)/$(1).a: $$(OBJS) $$(DEP_OBJS_$(1)) $$(DEP_LIBS_$(1)) $$(DEPENDS_$(1))\n\t@mkdir -p $$(LIBODIR)\n\t$$(if $$(filter %.a,$$?),mkdir -p $$(EXTRACT_DIR)_$(1))\n\t$$(if $$(filter %.a,$$?),cd $$(EXTRACT_DIR)_$(1); $$(foreach lib,$$(filter %.a,$$?),$$(AR) xo $$(UP_EXTRACT_DIR)/$$(lib);))\n\t$$(AR) ru $$@ $$(filter %.o,$$?) $$(if $$(filter %.a,$$?),$$(EXTRACT_DIR)_$(1)/*.o)\n\t$$(if $$(filter %.a,$$?),$$(RM) -r $$(EXTRACT_DIR)_$(1))\nendef\n\ndefine MakeImage\nDEP_LIBS_$(1) = $$(foreach lib,$$(filter %.a,$$(COMPONENTS_$(1))),$$(dir $$(lib))$$(LIBODIR)/$$(notdir $$(lib)))\nDEP_OBJS_$(1) = $$(foreach obj,$$(filter %.o,$$(COMPONENTS_$(1))),$$(dir $$(obj))$$(OBJODIR)/$$(notdir $$(obj)))\n$$(IMAGEODIR)/$(1).out: $$(OBJS) $$(DEP_OBJS_$(1)) $$(DEP_LIBS_$(1)) $$(DEPENDS_$(1))\n\t@mkdir -p $$(IMAGEODIR)\n\t$$(CC) $$(LDFLAGS) $$(if $$(LINKFLAGS_$(1)),$$(LINKFLAGS_$(1)),$$(LINKFLAGS_DEFAULT) $$(OBJS) $$(DEP_OBJS_$(1)) $$(DEP_LIBS_$(1))) -o $$@ \nendef\n\n$(BINODIR)/%.bin: $(IMAGEODIR)/%.out\n\t@mkdir -p $(BINODIR)\n\t$(ESPTOOL) elf2image $< -o $(FIRMWAREDIR)\n\n#############################################################\n# Rules base\n# Should be done in top-level makefile only\n#\n\nall: .subdirs $(OBJS) $(OLIBS) $(OIMAGES) $(OBINS) $(SPECIAL_MKTARGETS) \n\nclean:\n\t$(foreach d, $(SUBDIRS), $(MAKE) -C $(d) clean;)\n\t$(RM) -r $(ODIR)/$(TARGET)/$(FLAVOR)\n\nclobber: $(SPECIAL_CLOBBER)\n\t$(foreach d, $(SUBDIRS), $(MAKE) -C $(d) clobber;)\n\t$(RM) -r $(ODIR)\n\nflash: \nifndef PDIR\n\t$(MAKE) -C ./app flash\nelse\n\t$(ESPTOOL) --port $(ESPPORT) write_flash 0x00000 $(FIRMWAREDIR)0x00000.bin 0x10000 $(FIRMWAREDIR)0x10000.bin\nendif\n\nhtml:\n\t$(MKFSTOOL) -s app/http/html/ -d app/http/rofs_data.c\n\n.subdirs:\n\t@set -e; $(foreach d, $(SUBDIRS), $(MAKE) -C $(d);)\n\n#.subdirs:\n#\t$(foreach d, $(SUBDIRS), $(MAKE) -C $(d))\n\nifneq ($(MAKECMDGOALS),clean)\nifneq ($(MAKECMDGOALS),clobber)\nifdef DEPS\nsinclude $(DEPS)\nendif\nendif\nendif\n\n$(OBJODIR)/%.o: %.c\n\t@mkdir -p $(OBJODIR);\n\t$(CC) $(if $(findstring $<,$(DSRCS)),$(DFLAGS),$(CFLAGS)) $(COPTS_$(*F)) -o $@ -c $<\n\n$(OBJODIR)/%.d: %.c\n\t@mkdir -p $(OBJODIR);\n\t@echo DEPEND: $(CC) -M $(CFLAGS) $<\n\t@set -e; rm -f $@; \\\n\t$(CC) -M $(CFLAGS) $< > $@.$$$$; \\\n\tsed 's,\\($*\\.o\\)[ :]*,$(OBJODIR)/\\1 $@ : ,g' < $@.$$$$ > $@; \\\n\trm -f $@.$$$$\n\n$(OBJODIR)/%.o: %.s\n\t@mkdir -p $(OBJODIR);\n\t$(CC) $(CFLAGS) -o $@ -c $<\n\n$(OBJODIR)/%.d: %.s\n\t@mkdir -p $(OBJODIR); \\\n\tset -e; rm -f $@; \\\n\t$(CC) -M $(CFLAGS) $< > $@.$$$$; \\\n\tsed 's,\\($*\\.o\\)[ :]*,$(OBJODIR)/\\1 $@ : ,g' < $@.$$$$ > $@; \\\n\trm -f $@.$$$$\n\n$(OBJODIR)/%.o: %.S\n\t@mkdir -p $(OBJODIR);\n\t$(CC) $(CFLAGS) -D__ASSEMBLER__ -o $@ -c $<\n\n$(OBJODIR)/%.d: %.S\n\t@mkdir -p $(OBJODIR); \\\n\tset -e; rm -f $@; \\\n\t$(CC) -M $(CFLAGS) $< > $@.$$$$; \\\n\tsed 's,\\($*\\.o\\)[ :]*,$(OBJODIR)/\\1 $@ : ,g' < $@.$$$$ > $@; \\\n\trm -f $@.$$$$\n\n$(foreach lib,$(GEN_LIBS),$(eval $(call ShortcutRule,$(lib),$(LIBODIR))))\n\n$(foreach image,$(GEN_IMAGES),$(eval $(call ShortcutRule,$(image),$(IMAGEODIR))))\n\n$(foreach bin,$(GEN_BINS),$(eval $(call ShortcutRule,$(bin),$(BINODIR))))\n\n$(foreach lib,$(GEN_LIBS),$(eval $(call MakeLibrary,$(basename $(lib)))))\n\n$(foreach image,$(GEN_IMAGES),$(eval $(call MakeImage,$(basename $(image)))))\n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include -I $(PDIR)include/$(TARGET)\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n"
  },
  {
    "path": "README.md",
    "content": "esp-ginx\n--------\n\n##Robust HTTP server for the ESP8266\n\nThis project was inspired esp-httpd by Sprite_tm, NodeMcu ( https://github.com/nodemcu/nodemcu-firmware ) and NGINX\n\nMain features\n=============\n\n1. Event-driven, single threaded. No blocking, nowhere.\n2. DNS Server built in, means we have a captive portal ( will open upon connection os most phones and computers )\n3. Host check, means we can ensure server is on here.com and not there.com\n4. Redirects ( so #2 will work )\n5. HTTP Method enforcement\n7. URL rewrite ( very simple one but gives us friendly urls)\n8. CGI ( similar to esp-httpd but with more features )\n9. CORS enabled \n10. Zero-copy ( or almost ) request parse, inspired on NGINX parse.\n11. ROFS compressed with gzip\n12. WebSockects! \n12. Bonus http client :)\n\nOverview\n-------\nAfter playing around with esp-httpd I decided to extend it and ended up deciding to take it to the next level.\nI've used the NodeMcu firmware as base, removed all the lua related code and got a solid framework to work on.\nLater I ported Joyent's http parser (https://github.com/joyent/http-parser), which is almost the NGINX implementation, to the esp and developed from there. \n\nThe File System\n---------------\nI personally didn't like the overhead of decompressing static files to send over http as in esp-httpd, so I created a rom file system that consists of a static FS descriptor and an array with the data concatenated. To keep size short, I compress the files with gzip and send the compressed data stream with the gzip content-encoding. I could fit the whole bootstrap css+js files even if I didn't need to, plus cats pictures to honor Sprite_tm.\n\nStatic files are placed in the folder 'html' and there's a tool written in python to create the file system. The file system in the end id just a c file.\nIssuing 'Make html' creates/updates the file system.\n\nThere's a Spiffs built on the firmware, so a next step should be use it instead, but for my needs right now a static FS is enough.\n\nCGI\n---\nI don't believe in template html for such low memory devices. I rather prefer the static html + json api approach. So that's what you will see. \n\nWhen a request arrives, the server will start to parse it and call a cgi dispatcher on several points of the process, mainly on the http parser callbacks. This allows me to reject a request even before the body was received for example. \nIt also allows me not to copy unnecessary data to the precious ESP memory. CGI functions can say which headers they need to read and the parser will extract them as the data comes. We never save the whole request on a buffer.\n\nCGI functions are very flexible. They can allow other rules to proccess or keep the processing to themselfs. We can plugin features like request filtering by inserting wildcard cgi functions on the pipe for example. CORS cgi will plug itself on the pre-headers received and post headers received only.\n\nDNS server and Captive Portal\n---------\nI wanted to have captive portal-like featured on the server.\nTo do so the first step was to compile our own version of LwIP stack so we can enable DNS server announce via DHCP. Fortunatelly NodeMCU had LwIP sources already.\nWe then need to answer some known domains queries with our own ip, so we can capture those requests. Iphones for example to detect captive portal will issue a request to some random apple owned domains expecting 200 OK response, if we respond those requests with a redirect, voilà, the phone will open a login page with anything we like. It also works on PCs, windows will issue a requet to msftncsi.com to check for internet connection. When we redirect it, it will open our esp-ginx server on our loved browser.\nThere's a list of knows domains on the DNS server. I could just answer all DNS queries with our esp ip, but it would then flood our little esp with nonsense http requests. \n\nWebsockets\n---\nWhy? Mostly because I didn't see it around.\nI use it to speed test the esp's tcp capabilities, so a very simple application is written on top of the websocket stack that will keep flushing tcp packets of the chosen size so we can measure how many bytes / second we receive on the other end.\n\nThe Demo\n--------\nThis demo application assumes:\n* Relays connects to GPIO 5 and 4\n* DHT22 sensor connected to GPIO 2\n\nYou can :\n* Scan available wifi networks\n* Connect to an wifi network\n* Direct test the relays \n* Read temperature and humidity data\n* Do a tcp speed test on ESP8266 using websockets ( no more discussion about it, data wins )\n* See the required pictures of cats\n\n![Speed Test](http://i.gyazo.com/89e3fcea70641e871a3bfbaf5d116d66.png)\n\n\n"
  },
  {
    "path": "app/.gitignore",
    "content": "*.output*\n!.gitignore\n"
  },
  {
    "path": "app/Makefile",
    "content": "#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of object file images to be generated ()\n#   GEN_BINS - list of binaries to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nTARGET = eagle\n#FLAVOR = release\nFLAVOR = debug\n\n#EXTRA_CCFLAGS += -u\n\nifndef PDIR # {\nGEN_IMAGES= eagle.app.v6.out\nGEN_BINS= eagle.app.v6.bin\nSPECIAL_MKTARGETS=$(APP_MKTARGETS)\nSUBDIRS=    \\\n    user \\\n    http \\\n    dns \\\n    driver \\\n    lwip \\\n    json \\\n    platform \\\n    libc \\\n    mqtt \\\n    smart \\\n    util \\\n    sensor \\\n    spiffs\n\nendif # } PDIR\n\nAPPDIR = .\nLDDIR = ../ld\n\nCCFLAGS += -Os\n\nTARGET_LDFLAGS =\t\t\\\n\t-nostdlib\t\t\\\n\t-Wl,-EL \\\n\t--longcalls \\\n\t--text-section-literals\n\nifeq ($(FLAVOR),debug)\n    TARGET_LDFLAGS += -g -O2\nendif\n\nifeq ($(FLAVOR),release)\n    TARGET_LDFLAGS += -g -O0\nendif\n\nLD_FILE = $(LDDIR)/eagle.app.v6.ld\n\nifeq ($(APP), 1)\n\tLD_FILE = $(LDDIR)/eagle.app.v6.app1.ld\nendif\n\nifeq ($(APP), 2)\n\tLD_FILE = $(LDDIR)/eagle.app.v6.app2.ld\nendif\n\nCOMPONENTS_eagle.app.v6 = \\\n    user/libuser.a \\\n    http/http.a \\\n    dns/dns.a \\\n    driver/libdriver.a \\\n    lwip/liblwip.a \\\n    json/libjson.a \\\n    platform/libplatform.a \\\n    libc/liblibc.a \\\n    mqtt/mqtt.a \\\n    smart/smart.a \\\n    util/util.a \\\n    sensor/sensors.a \\\n    spiffs/spiffs.a\n\n\nLINKFLAGS_eagle.app.v6 = \\\n\t-L../lib        \\\n\t-nostdlib\t\\\n    -T$(LD_FILE)   \\\n\t-Wl,--no-check-sections\t\\\n    -u call_user_start\t\\\n\t-Wl,-static\t\\\n\t-Wl,--start-group\t\\\n\t-lc\t\\\n\t-lgcc\t\\\n\t-lhal\t\\\n\t-lphy\t\\\n\t-lpp\t\\\n\t-lnet80211\t\\\n\t-lwpa\t\\\n\t-lmain\t\\\n\t-ljson\t\\\n\t-lsmartconfig\t\\\n\t-lssl\t\\\n\t$(DEP_LIBS_eagle.app.v6)\t\\\n\t-Wl,--end-group\n\nDEPENDS_eagle.app.v6 = \\\n                $(LD_FILE) \\\n                $(LDDIR)/eagle.rom.addr.v6.ld\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n\n#UNIVERSAL_TARGET_DEFINES =\t\t\\\n\n# Other potential configuration flags include:\n#\t-DTXRX_TXBUF_DEBUG\n#\t-DTXRX_RXBUF_DEBUG\n#\t-DWLAN_CONFIG_CCX\nCONFIGURATION_DEFINES =\t-D__ets__ \\\n\t\t\t-DICACHE_FLASH\t\\\n\t\t\t-DLWIP_OPEN_SRC\t\\\n\t\t\t-DPBUF_RSV_FOR_WLAN\t\\\n\t\t\t-DEBUF_LWIP\n\nDEFINES +=\t\t\t\t\\\n\t$(UNIVERSAL_TARGET_DEFINES)\t\\\n\t$(CONFIGURATION_DEFINES)\n\nDDEFINES +=\t\t\t\t\\\n\t$(UNIVERSAL_TARGET_DEFINES)\t\\\n\t$(CONFIGURATION_DEFINES)\n\n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n\n.PHONY: FORCE\nFORCE:\n"
  },
  {
    "path": "app/dns/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = dns.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../libc\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/dns/dns.c",
    "content": "#include \"c_types.h\"\n#include \"user_interface.h\"\n#include \"user_config.h\"\n#include \"espconn.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n\n//Listening connection data\nstatic struct espconn dnsConn;\nstatic esp_udp dnsUdp;\n\nstatic const char *localDomains[]={\n    INTERFACE_DOMAIN, //because I can be anybody\n\n    //captive portal domains\n    \"google.com\", //android , yes I can be Google too    \n    \"gsp1.apple.com\", //iphone\n    \"akamaitechnologies.com\",\n    \"apple.com\",\n    \"appleiphonecell.com\",\n    \"itools.info\",\n    \"ibook.info\",\n    \"airport.us\",\n    \"thinkdifferent.us\",\n    \"apple.com.edgekey.net\",\n    \"akamaiedge.net\",   \n    \"msftncsi.com\", //for windows and windows phone,\n    \"microsoft.com\",\n    NULL\n};\n\nstatic int ICACHE_FLASH_ATTR isKnownDNS(char *dns){\n\n    int i=0;    \n    while(true){\n\n        const char *cmp = localDomains[i];\n\n        if(cmp==NULL)\n            break;\n\n        if(strstr(dns,cmp))\n            return 1;\n\n        i++;\n    }\n\n    return 0;\n}\n\nstatic void ICACHE_FLASH_ATTR dnsQueryReceived(void *arg, char *data, unsigned short length) {\n\n\n// parse incoming query domain\n    char domain[30];\n    char *writePos=domain;\n    memset(domain,0,30);\n    \n    int offSet=12;   \n    int len=data[offSet];\n    while(len!=0 && offSet<length){\n\n        offSet++;\n        memcpy(writePos,data+offSet,len);\n        writePos+=len; //advance\n        offSet+=len;\n        len=data[offSet];\n\n        if(len!=0){\n            *writePos='.';            \n            writePos++;\n        }\n             \n    }\n\n    NODE_DBG(\"DNS Query Received: %s\",domain);\n    if(!isKnownDNS(domain))\n       return;\n\n    \n\n    struct espconn *conn=arg;\n  //build response\n    char response[100] = {data[0], data[1],\n                0b10000100 | (0b00000001 & data[2]), //response, authorative answer, not truncated, copy the recursion bit\n                0b00000000, //no recursion available, no errors\n                data[4], data[5], //Question count\n                data[4], data[5], //answer count\n                0x00, 0x00,       //NS record count\n                0x00, 0x00};      //Resource record count\n\n    int idx = 12;\n    memcpy(response+12, data+12, length-12); //Copy the rest of the query section\n    idx += length-12;\n\n    //Set a pointer to the domain name in the question section\n    response[idx] = 0xC0;\n    response[idx+1] = 0x0C;\n\n    //Set the type to \"Host Address\"\n    response[idx+2] = 0x00;\n    response[idx+3] = 0x01;\n\n    //Set the response class to IN\n    response[idx+4] = 0x00;\n    response[idx+5] = 0x01;\n\n    //A 32 bit integer specifying TTL in seconds, 0 means no caching\n    response[idx+6] = 0x00;\n    response[idx+7] = 0x00;\n    response[idx+8] = 0x00;\n    response[idx+9] = 0x00;\n\n    //RDATA length\n    response[idx+10] = 0x00;\n    response[idx+11] = 0x04; //4 byte IP address\n\n    //The IP address\n    response[idx + 12] = 192;\n    response[idx + 13] = 168;\n    response[idx + 14] = 4;\n    response[idx + 15] = 1;\n\n    int ret = espconn_sendto(conn, (uint8_t*)response, idx+16);\n    uint8_t *ip = conn->proto.udp->remote_ip;\n\n    //NODE_DBG(\"UDP send res : %d ip: %d.%d.%d.%d , port: %d\",ret,ip[0],ip[1],ip[2],ip[3],conn->proto.udp->remote_port);\n}\n\nvoid ICACHE_FLASH_ATTR init_dns() {\n\t\n    uint8_t mode = 1;\n    wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode);\n    wifi_set_broadcast_if(3);\n    //espconn_disconnect(&dnsConn);\n    espconn_delete(&dnsConn);\n\n\tdnsConn.type=ESPCONN_UDP;\n\tdnsConn.state=ESPCONN_NONE;\n\tdnsUdp.local_port=(int)53;\n\tdnsConn.proto.udp=&dnsUdp;\t\n\t\n    espconn_regist_recvcb(&dnsConn, dnsQueryReceived);   \n\n\tint res = espconn_create(&dnsConn);\n\n    NODE_DBG(\"DNS server init, conn=%p , status=%d\", &dnsConn,res);\n\n}"
  },
  {
    "path": "app/dns/dns.h",
    "content": "#ifndef DNS_H\n#define DNS_H\n\nvoid ICACHE_FLASH_ATTR init_dns();\n\n#endif"
  },
  {
    "path": "app/driver/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = libdriver.a\nendif\n\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../\nINCLUDES += -I ../platform\nINCLUDES += -I ../libc\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/driver/gpio16.c",
    "content": "#include \"ets_sys.h\"\n#include \"osapi.h\"\n#include \"driver/gpio16.h\"\n\nvoid ICACHE_FLASH_ATTR\ngpio16_output_conf(void)\n{\n    WRITE_PERI_REG(PAD_XPD_DCDC_CONF,\n                   (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); \t// mux configuration for XPD_DCDC to output rtc_gpio0\n\n    WRITE_PERI_REG(RTC_GPIO_CONF,\n                   (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0);\t//mux configuration for out enable\n\n    WRITE_PERI_REG(RTC_GPIO_ENABLE,\n                   (READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe) | (uint32)0x1);\t//out enable\n}\n\nvoid ICACHE_FLASH_ATTR\ngpio16_output_set(uint8 value)\n{\n    WRITE_PERI_REG(RTC_GPIO_OUT,\n                   (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe) | (uint32)(value & 1));\n}\n\nvoid ICACHE_FLASH_ATTR\ngpio16_input_conf(void)\n{\n    WRITE_PERI_REG(PAD_XPD_DCDC_CONF,\n                   (READ_PERI_REG(PAD_XPD_DCDC_CONF) & 0xffffffbc) | (uint32)0x1); \t// mux configuration for XPD_DCDC and rtc_gpio0 connection\n\n    WRITE_PERI_REG(RTC_GPIO_CONF,\n                   (READ_PERI_REG(RTC_GPIO_CONF) & (uint32)0xfffffffe) | (uint32)0x0);\t//mux configuration for out enable\n\n    WRITE_PERI_REG(RTC_GPIO_ENABLE,\n                   READ_PERI_REG(RTC_GPIO_ENABLE) & (uint32)0xfffffffe);\t//out disable\n}\n\nuint8 ICACHE_FLASH_ATTR\ngpio16_input_get(void)\n{\n    return (uint8)(READ_PERI_REG(RTC_GPIO_IN_DATA) & 1);\n}\n"
  },
  {
    "path": "app/driver/i2c_master.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: i2c_master.c\n *\n * Description: i2c master API\n *\n * Modification history:\n *     2014/3/12, v1.0 create this file.\n*******************************************************************************/\n#include \"ets_sys.h\"\n#include \"osapi.h\"\n#include \"gpio.h\"\n\n#include \"driver/i2c_master.h\"\n\n#include \"pin_map.h\"\n\nLOCAL uint8 m_nLastSDA;\nLOCAL uint8 m_nLastSCL;\n\nLOCAL uint8 pinSDA = 2;\nLOCAL uint8 pinSCL = 15;\n\n/******************************************************************************\n * FunctionName : i2c_master_setDC\n * Description  : Internal used function -\n *                    set i2c SDA and SCL bit value for half clk cycle\n * Parameters   : uint8 SDA\n *                uint8 SCL\n * Returns      : NONE\n*******************************************************************************/\nLOCAL void ICACHE_FLASH_ATTR\ni2c_master_setDC(uint8 SDA, uint8 SCL)\n{\n    SDA\t&= 0x01;\n    SCL\t&= 0x01;\n    m_nLastSDA = SDA;\n    m_nLastSCL = SCL;\n\n    if ((0 == SDA) && (0 == SCL)) {\n        I2C_MASTER_SDA_LOW_SCL_LOW();\n    } else if ((0 == SDA) && (1 == SCL)) {\n        I2C_MASTER_SDA_LOW_SCL_HIGH();\n    } else if ((1 == SDA) && (0 == SCL)) {\n        I2C_MASTER_SDA_HIGH_SCL_LOW();\n    } else {\n        I2C_MASTER_SDA_HIGH_SCL_HIGH();\n    }\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_getDC\n * Description  : Internal used function -\n *                    get i2c SDA bit value\n * Parameters   : NONE\n * Returns      : uint8 - SDA bit value\n*******************************************************************************/\nLOCAL uint8 ICACHE_FLASH_ATTR\ni2c_master_getDC(void)\n{\n    uint8 sda_out;\n    sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));\n    return sda_out;\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_init\n * Description  : initilize I2C bus to enable i2c operations\n * Parameters   : NONE\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\ni2c_master_init(void)\n{\n    uint8 i;\n\n    i2c_master_setDC(1, 0);\n    i2c_master_wait(5);\n\n    // when SCL = 0, toggle SDA to clear up\n    i2c_master_setDC(0, 0) ;\n    i2c_master_wait(5);\n    i2c_master_setDC(1, 0) ;\n    i2c_master_wait(5);\n\n    // set data_cnt to max value\n    for (i = 0; i < 28; i++) {\n        i2c_master_setDC(1, 0);\n        i2c_master_wait(5);\t// sda 1, scl 0\n        i2c_master_setDC(1, 1);\n        i2c_master_wait(5);\t// sda 1, scl 1\n    }\n\n    // reset all\n    i2c_master_stop();\n    return;\n}\n\nuint8 i2c_master_get_pinSDA(){\n    return pinSDA;\n}\n\nuint8 i2c_master_get_pinSCL(){\n    return pinSCL;\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_gpio_init\n * Description  : config SDA and SCL gpio to open-drain output mode,\n *                mux and gpio num defined in i2c_master.h\n * Parameters   : NONE\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\ni2c_master_gpio_init(uint8 sda, uint8 scl)\n{\n    pinSDA = pin_num[sda];\n    pinSCL = pin_num[scl];\n\n    ETS_GPIO_INTR_DISABLE() ;\n//    ETS_INTR_LOCK();\n\n    PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC);\n    PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC);\n\n    GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;\n    GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SDA_GPIO));\n    GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO)), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;\n    GPIO_REG_WRITE(GPIO_ENABLE_ADDRESS, GPIO_REG_READ(GPIO_ENABLE_ADDRESS) | (1 << I2C_MASTER_SCL_GPIO));\n\n    I2C_MASTER_SDA_HIGH_SCL_HIGH();\n\n    ETS_GPIO_INTR_ENABLE() ;\n//    ETS_INTR_UNLOCK();\n\n    i2c_master_init();\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_start\n * Description  : set i2c to send state\n * Parameters   : NONE\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\ni2c_master_start(void)\n{\n    i2c_master_setDC(1, m_nLastSCL);\n    i2c_master_wait(5);\n    i2c_master_setDC(1, 1);\n    i2c_master_wait(5);\t// sda 1, scl 1\n    i2c_master_setDC(0, 1);\n    i2c_master_wait(5);\t// sda 0, scl 1\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_stop\n * Description  : set i2c to stop sending state\n * Parameters   : NONE\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\ni2c_master_stop(void)\n{\n    i2c_master_wait(5);\n\n    i2c_master_setDC(0, m_nLastSCL);\n    i2c_master_wait(5);\t// sda 0\n    i2c_master_setDC(0, 1);\n    i2c_master_wait(5);\t// sda 0, scl 1\n    i2c_master_setDC(1, 1);\n    i2c_master_wait(5);\t// sda 1, scl 1\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_setAck\n * Description  : set ack to i2c bus as level value\n * Parameters   : uint8 level - 0 or 1\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\ni2c_master_setAck(uint8 level)\n{\n    i2c_master_setDC(m_nLastSDA, 0);\n    i2c_master_wait(5);\n    i2c_master_setDC(level, 0);\n    i2c_master_wait(5);\t// sda level, scl 0\n    i2c_master_setDC(level, 1);\n    i2c_master_wait(8);\t// sda level, scl 1\n    i2c_master_setDC(level, 0);\n    i2c_master_wait(5);\t// sda level, scl 0\n    i2c_master_setDC(1, 0);\n    i2c_master_wait(5);\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_getAck\n * Description  : confirm if peer send ack\n * Parameters   : NONE\n * Returns      : uint8 - ack value, 0 or 1\n*******************************************************************************/\nuint8 ICACHE_FLASH_ATTR\ni2c_master_getAck(void)\n{\n    uint8 retVal;\n    i2c_master_setDC(m_nLastSDA, 0);\n    i2c_master_wait(5);\n    i2c_master_setDC(1, 0);\n    i2c_master_wait(5);\n    i2c_master_setDC(1, 1);\n    i2c_master_wait(5);\n\n    retVal = i2c_master_getDC();\n    i2c_master_wait(5);\n    i2c_master_setDC(1, 0);\n    i2c_master_wait(5);\n\n    return retVal;\n}\n\n/******************************************************************************\n* FunctionName : i2c_master_checkAck\n* Description  : get dev response\n* Parameters   : NONE\n* Returns      : true : get ack ; false : get nack\n*******************************************************************************/\nbool ICACHE_FLASH_ATTR\ni2c_master_checkAck(void)\n{\n    if(i2c_master_getAck()){\n        return FALSE;\n    }else{\n        return TRUE;\n    }\n}\n\n/******************************************************************************\n* FunctionName : i2c_master_send_ack\n* Description  : response ack\n* Parameters   : NONE\n* Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\ni2c_master_send_ack(void)\n{\n    i2c_master_setAck(0x0);\n}\n/******************************************************************************\n* FunctionName : i2c_master_send_nack\n* Description  : response nack\n* Parameters   : NONE\n* Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\ni2c_master_send_nack(void)\n{\n    i2c_master_setAck(0x1);\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_readByte\n * Description  : read Byte from i2c bus\n * Parameters   : NONE\n * Returns      : uint8 - readed value\n*******************************************************************************/\nuint8 ICACHE_FLASH_ATTR\ni2c_master_readByte(void)\n{\n    uint8 retVal = 0;\n    uint8 k, i;\n\n    i2c_master_wait(5);\n    i2c_master_setDC(m_nLastSDA, 0);\n    i2c_master_wait(5);\t// sda 1, scl 0\n\n    for (i = 0; i < 8; i++) {\n        i2c_master_wait(5);\n        i2c_master_setDC(1, 0);\n        i2c_master_wait(5);\t// sda 1, scl 0\n        i2c_master_setDC(1, 1);\n        i2c_master_wait(5);\t// sda 1, scl 1\n\n        k = i2c_master_getDC();\n        i2c_master_wait(5);\n\n        if (i == 7) {\n            i2c_master_wait(3);   ////\n        }\n\n        k <<= (7 - i);\n        retVal |= k;\n    }\n\n    i2c_master_setDC(1, 0);\n    i2c_master_wait(5);\t// sda 1, scl 0\n\n    return retVal;\n}\n\n/******************************************************************************\n * FunctionName : i2c_master_writeByte\n * Description  : write wrdata value(one byte) into i2c\n * Parameters   : uint8 wrdata - write value\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\ni2c_master_writeByte(uint8 wrdata)\n{\n    uint8 dat;\n    sint8 i;\n\n    i2c_master_wait(5);\n\n    i2c_master_setDC(m_nLastSDA, 0);\n    i2c_master_wait(5);\n\n    for (i = 7; i >= 0; i--) {\n        dat = wrdata >> i;\n        i2c_master_setDC(dat, 0);\n        i2c_master_wait(5);\n        i2c_master_setDC(dat, 1);\n        i2c_master_wait(5);\n\n        if (i == 0) {\n            i2c_master_wait(3);   ////\n        }\n\n        i2c_master_setDC(dat, 0);\n        i2c_master_wait(5);\n    }\n}\n"
  },
  {
    "path": "app/driver/key.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: key.c\n *\n * Description: key driver, now can use different gpio and install different function\n *\n * Modification history:\n *     2014/5/1, v1.0 create this file.\n*******************************************************************************/\n#include \"ets_sys.h\"\n#include \"os_type.h\"\n#include \"osapi.h\"\n#include \"mem.h\"\n#include \"gpio.h\"\n#include \"user_interface.h\"\n\n#include \"driver/key.h\"\n\nLOCAL void key_intr_handler(struct keys_param *keys);\n\n/******************************************************************************\n * FunctionName : key_init_single\n * Description  : init single key's gpio and register function\n * Parameters   : uint8 gpio_id - which gpio to use\n *                uint32 gpio_name - gpio mux name\n *                uint32 gpio_func - gpio function\n *                key_function long_press - long press function, needed to install\n *                key_function short_press - short press function, needed to install\n * Returns      : single_key_param - single key parameter, needed by key init\n*******************************************************************************/\nstruct single_key_param *ICACHE_FLASH_ATTR\nkey_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press)\n{\n    struct single_key_param *single_key = (struct single_key_param *)os_zalloc(sizeof(struct single_key_param));\n\n    single_key->gpio_id = gpio_id;\n    single_key->gpio_name = gpio_name;\n    single_key->gpio_func = gpio_func;\n    single_key->long_press = long_press;\n    single_key->short_press = short_press;\n\n    return single_key;\n}\n\n/******************************************************************************\n * FunctionName : key_init\n * Description  : init keys\n * Parameters   : key_param *keys - keys parameter, which inited by key_init_single\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nkey_init(struct keys_param *keys)\n{\n    uint8 i;\n\n    ETS_GPIO_INTR_ATTACH(key_intr_handler, keys);\n\n    ETS_GPIO_INTR_DISABLE();\n\n    for (i = 0; i < keys->key_num; i++) {\n        keys->single_key[i]->key_level = 1;\n\n        PIN_FUNC_SELECT(keys->single_key[i]->gpio_name, keys->single_key[i]->gpio_func);\n\n        gpio_output_set(0, 0, 0, GPIO_ID_PIN(keys->single_key[i]->gpio_id));\n\n        gpio_register_set(GPIO_PIN_ADDR(keys->single_key[i]->gpio_id), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)\n                          | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE)\n                          | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));\n\n        //clear gpio14 status\n        GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(keys->single_key[i]->gpio_id));\n\n        //enable interrupt\n        gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_NEGEDGE);\n    }\n\n    ETS_GPIO_INTR_ENABLE();\n}\n\n/******************************************************************************\n * FunctionName : key_5s_cb\n * Description  : long press 5s timer callback\n * Parameters   : single_key_param *single_key - single key parameter\n * Returns      : none\n*******************************************************************************/\nLOCAL void ICACHE_FLASH_ATTR\nkey_5s_cb(struct single_key_param *single_key)\n{\n    os_timer_disarm(&single_key->key_5s);\n\n    // low, then restart\n    if (0 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {\n        if (single_key->long_press) {\n            single_key->long_press();\n        }\n    }\n}\n\n/******************************************************************************\n * FunctionName : key_50ms_cb\n * Description  : 50ms timer callback to check it's a real key push\n * Parameters   : single_key_param *single_key - single key parameter\n * Returns      : none\n*******************************************************************************/\nLOCAL void ICACHE_FLASH_ATTR\nkey_50ms_cb(struct single_key_param *single_key)\n{\n    os_timer_disarm(&single_key->key_50ms);\n\n    // high, then key is up\n    if (1 == GPIO_INPUT_GET(GPIO_ID_PIN(single_key->gpio_id))) {\n        os_timer_disarm(&single_key->key_5s);\n        single_key->key_level = 1;\n        gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_NEGEDGE);\n\n        if (single_key->short_press) {\n            single_key->short_press();\n        }\n    } else {\n        gpio_pin_intr_state_set(GPIO_ID_PIN(single_key->gpio_id), GPIO_PIN_INTR_POSEDGE);\n    }\n}\n\n/******************************************************************************\n * FunctionName : key_intr_handler\n * Description  : key interrupt handler\n * Parameters   : key_param *keys - keys parameter, which inited by key_init_single\n * Returns      : none\n*******************************************************************************/\nLOCAL void\nkey_intr_handler(struct keys_param *keys)\n{\n    uint8 i;\n    uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);\n\n    for (i = 0; i < keys->key_num; i++) {\n        if (gpio_status & BIT(keys->single_key[i]->gpio_id)) {\n            //disable interrupt\n            gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_DISABLE);\n\n            //clear interrupt status\n            GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(keys->single_key[i]->gpio_id));\n\n            if (keys->single_key[i]->key_level == 1) {\n                // 5s, restart & enter softap mode\n                os_timer_disarm(&keys->single_key[i]->key_5s);\n                os_timer_setfn(&keys->single_key[i]->key_5s, (os_timer_func_t *)key_5s_cb, keys->single_key[i]);\n                os_timer_arm(&keys->single_key[i]->key_5s, 5000, 0);\n                keys->single_key[i]->key_level = 0;\n                gpio_pin_intr_state_set(GPIO_ID_PIN(keys->single_key[i]->gpio_id), GPIO_PIN_INTR_POSEDGE);\n            } else {\n                // 50ms, check if this is a real key up\n                os_timer_disarm(&keys->single_key[i]->key_50ms);\n                os_timer_setfn(&keys->single_key[i]->key_50ms, (os_timer_func_t *)key_50ms_cb, keys->single_key[i]);\n                os_timer_arm(&keys->single_key[i]->key_50ms, 50, 0);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "app/driver/onewire.c",
    "content": "/*\nAdaptation of Paul Stoffregen's One wire library to the NodeMcu\n\nThe latest version of this library may be found at:\n  http://www.pjrc.com/teensy/td_libs_OneWire.html\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe 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 OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nMuch of the code was inspired by Derek Yerger's code, though I don't\nthink much of that remains.  In any event that was..\n    (copyleft) 2006 by Derek Yerger - Free to distribute freely.\n\nThe CRC code was excerpted and inspired by the Dallas Semiconductor\nsample code bearing this copyright.\n//---------------------------------------------------------------------------\n// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the\n// Software is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\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\n// MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES\n// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n// OTHER DEALINGS IN THE SOFTWARE.\n//\n// Except as contained in this notice, the name of Dallas Semiconductor\n// shall not be used except as stated in the Dallas Semiconductor\n// Branding Policy.\n//--------------------------------------------------------------------------\n*/\n\n#include \"driver/onewire.h\"\n#include \"platform.h\"\n#include \"osapi.h\"\n\n#define noInterrupts ets_intr_lock\n#define interrupts ets_intr_unlock\n#define delayMicroseconds os_delay_us\n\n#if ONEWIRE_SEARCH\n// global search state\nstatic unsigned char ROM_NO[NUM_OW][8];\nstatic uint8_t LastDiscrepancy[NUM_OW];\nstatic uint8_t LastFamilyDiscrepancy[NUM_OW];\nstatic uint8_t LastDeviceFlag[NUM_OW];\n#endif\n\nvoid onewire_init(uint8_t pin)\n{\n\t// pinMode(pin, INPUT);\n  platform_gpio_mode(pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP);\n#if ONEWIRE_SEARCH\n\tonewire_reset_search(pin);\n#endif\n}\n\n\n// Perform the onewire reset function.  We will wait up to 250uS for\n// the bus to come high, if it doesn't then it is broken or shorted\n// and we return a 0;\n//\n// Returns 1 if a device asserted a presence pulse, 0 otherwise.\n//\nuint8_t onewire_reset(uint8_t pin)\n{\n\tuint8_t r;\n\tuint8_t retries = 125;\n\n\tnoInterrupts();\n\tDIRECT_MODE_INPUT(pin);\n\tinterrupts();\n\t// wait until the wire is high... just in case\n\tdo {\n\t\tif (--retries == 0) return 0;\n\t\tdelayMicroseconds(2);\n\t} while ( !DIRECT_READ(pin));\n\n\tnoInterrupts();\n\tDIRECT_WRITE_LOW(pin);\n\tDIRECT_MODE_OUTPUT(pin);\t// drive output low\n\tinterrupts();\n\tdelayMicroseconds(480);\n\tnoInterrupts();\n\tDIRECT_MODE_INPUT(pin);\t// allow it to float\n\tdelayMicroseconds(70);\n\tr = !DIRECT_READ(pin);\n\tinterrupts();\n\tdelayMicroseconds(410);\n\treturn r;\n}\n\n//\n// Write a bit. Port and bit is used to cut lookup time and provide\n// more certain timing.\n//\nstatic void onewire_write_bit(uint8_t pin, uint8_t v)\n{\n\tif (v & 1) {\n\t\tnoInterrupts();\n\t\tDIRECT_WRITE_LOW(pin);\n\t\tDIRECT_MODE_OUTPUT(pin);\t// drive output low\n\t\tdelayMicroseconds(10);\n\t\tDIRECT_WRITE_HIGH(pin);\t// drive output high\n\t\tinterrupts();\n\t\tdelayMicroseconds(55);\n\t} else {\n\t\tnoInterrupts();\n\t\tDIRECT_WRITE_LOW(pin);\n\t\tDIRECT_MODE_OUTPUT(pin);\t// drive output low\n\t\tdelayMicroseconds(65);\n\t\tDIRECT_WRITE_HIGH(pin);\t// drive output high\n\t\tinterrupts();\n\t\tdelayMicroseconds(5);\n\t}\n}\n\n//\n// Read a bit. Port and bit is used to cut lookup time and provide\n// more certain timing.\n//\nstatic uint8_t onewire_read_bit(uint8_t pin)\n{\n\tuint8_t r;\n\n\tnoInterrupts();\n\tDIRECT_MODE_OUTPUT(pin);\n\tDIRECT_WRITE_LOW(pin);\n\tdelayMicroseconds(3);\n\tDIRECT_MODE_INPUT(pin);\t// let pin float, pull up will raise\n\tdelayMicroseconds(10);\n\tr = DIRECT_READ(pin);\n\tinterrupts();\n\tdelayMicroseconds(53);\n\treturn r;\n}\n\n//\n// Write a byte. The writing code uses the active drivers to raise the\n// pin high, if you need power after the write (e.g. DS18S20 in\n// parasite power mode) then set 'power' to 1, otherwise the pin will\n// go tri-state at the end of the write to avoid heating in a short or\n// other mishap.\n//\nvoid onewire_write(uint8_t pin, uint8_t v, uint8_t power /* = 0 */) {\n  uint8_t bitMask;\n\n  for (bitMask = 0x01; bitMask; bitMask <<= 1) {\n\t  onewire_write_bit(pin, (bitMask & v)?1:0);\n  }\n  if ( !power) {\n  \tnoInterrupts();\n  \tDIRECT_MODE_INPUT(pin);\n  \tDIRECT_WRITE_LOW(pin);\n  \tinterrupts();\n  }\n}\n\nvoid onewire_write_bytes(uint8_t pin, const uint8_t *buf, uint16_t count, bool power /* = 0 */) {\n  uint16_t i;\n  for (i = 0 ; i < count ; i++)\n    onewire_write(pin, buf[i], 0);\n  if (!power) {\n    noInterrupts();\n    DIRECT_MODE_INPUT(pin);\n    DIRECT_WRITE_LOW(pin);\n    interrupts();\n  }\n}\n\n//\n// Read a byte\n//\nuint8_t onewire_read(uint8_t pin) {\n  uint8_t bitMask;\n  uint8_t r = 0;\n\n  for (bitMask = 0x01; bitMask; bitMask <<= 1) {\n  \tif (onewire_read_bit(pin)) r |= bitMask;\n  }\n  return r;\n}\n\nvoid onewire_read_bytes(uint8_t pin, uint8_t *buf, uint16_t count) {\n  uint16_t i;\n  for (i = 0 ; i < count ; i++)\n    buf[i] = onewire_read(pin);\n}\n\n//\n// Do a ROM select\n//\nvoid onewire_select(uint8_t pin, const uint8_t rom[8])\n{\n    uint8_t i;\n\n    onewire_write(pin, 0x55, 0);           // Choose ROM\n\n    for (i = 0; i < 8; i++) onewire_write(pin, rom[i], 0);\n}\n\n//\n// Do a ROM skip\n//\nvoid onewire_skip(uint8_t pin)\n{\n    onewire_write(pin, 0xCC, 0);           // Skip ROM\n}\n\nvoid onewire_depower(uint8_t pin)\n{\n\tnoInterrupts();\n\tDIRECT_MODE_INPUT(pin);\n\tinterrupts();\n}\n\n#if ONEWIRE_SEARCH\n\n//\n// You need to use this function to start a search again from the beginning.\n// You do not need to do it for the first search, though you could.\n//\nvoid onewire_reset_search(uint8_t pin)\n{\n  // reset the search state\n  LastDiscrepancy[pin] = 0;\n  LastDeviceFlag[pin] = FALSE;\n  LastFamilyDiscrepancy[pin] = 0;\n  int i;\n  for(i = 7; ; i--) {\n    ROM_NO[pin][i] = 0;\n    if ( i == 0) break;\n  }\n}\n\n// Setup the search to find the device type 'family_code' on the next call\n// to search(*newAddr) if it is present.\n//\nvoid onewire_target_search(uint8_t pin, uint8_t family_code)\n{\n   // set the search state to find SearchFamily type devices\n   ROM_NO[pin][0] = family_code;\n   uint8_t i;\n   for (i = 1; i < 8; i++)\n      ROM_NO[pin][i] = 0;\n   LastDiscrepancy[pin] = 64;\n   LastFamilyDiscrepancy[pin] = 0;\n   LastDeviceFlag[pin] = FALSE;\n}\n\n//\n// Perform a search. If this function returns a '1' then it has\n// enumerated the next device and you may retrieve the ROM from the\n// OneWire::address variable. If there are no devices, no further\n// devices, or something horrible happens in the middle of the\n// enumeration then a 0 is returned.  If a new device is found then\n// its address is copied to newAddr.  Use OneWire::reset_search() to\n// start over.\n//\n// --- Replaced by the one from the Dallas Semiconductor web site ---\n//--------------------------------------------------------------------------\n// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing\n// search state.\n// Return TRUE  : device found, ROM number in ROM_NO buffer\n//        FALSE : device not found, end of search\n//\nuint8_t onewire_search(uint8_t pin, uint8_t *newAddr)\n{\n   uint8_t id_bit_number;\n   uint8_t last_zero, rom_byte_number, search_result;\n   uint8_t id_bit, cmp_id_bit;\n\n   unsigned char rom_byte_mask, search_direction;\n\n   // initialize for search\n   id_bit_number = 1;\n   last_zero = 0;\n   rom_byte_number = 0;\n   rom_byte_mask = 1;\n   search_result = 0;\n\n   // if the last call was not the last one\n   if (!LastDeviceFlag[pin])\n   {\n      // 1-Wire reset\n      if (!onewire_reset(pin))\n      {\n         // reset the search\n         LastDiscrepancy[pin] = 0;\n         LastDeviceFlag[pin] = FALSE;\n         LastFamilyDiscrepancy[pin] = 0;\n         return FALSE;\n      }\n\n      // issue the search command\n      onewire_write(pin, 0xF0, 0);\n\n      // loop to do the search\n      do\n      {\n         // read a bit and its complement\n         id_bit = onewire_read_bit(pin);\n         cmp_id_bit = onewire_read_bit(pin);\n\n         // check for no devices on 1-wire\n         if ((id_bit == 1) && (cmp_id_bit == 1))\n            break;\n         else\n         {\n            // all devices coupled have 0 or 1\n            if (id_bit != cmp_id_bit)\n               search_direction = id_bit;  // bit write value for search\n            else\n            {\n               // if this discrepancy if before the Last Discrepancy\n               // on a previous next then pick the same as last time\n               if (id_bit_number < LastDiscrepancy[pin])\n                  search_direction = ((ROM_NO[pin][rom_byte_number] & rom_byte_mask) > 0);\n               else\n                  // if equal to last pick 1, if not then pick 0\n                  search_direction = (id_bit_number == LastDiscrepancy[pin]);\n\n               // if 0 was picked then record its position in LastZero\n               if (search_direction == 0)\n               {\n                  last_zero = id_bit_number;\n\n                  // check for Last discrepancy in family\n                  if (last_zero < 9)\n                     LastFamilyDiscrepancy[pin] = last_zero;\n               }\n            }\n\n            // set or clear the bit in the ROM byte rom_byte_number\n            // with mask rom_byte_mask\n            if (search_direction == 1)\n              ROM_NO[pin][rom_byte_number] |= rom_byte_mask;\n            else\n              ROM_NO[pin][rom_byte_number] &= ~rom_byte_mask;\n\n            // serial number search direction write bit\n            onewire_write_bit(pin, search_direction);\n\n            // increment the byte counter id_bit_number\n            // and shift the mask rom_byte_mask\n            id_bit_number++;\n            rom_byte_mask <<= 1;\n\n            // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask\n            if (rom_byte_mask == 0)\n            {\n                rom_byte_number++;\n                rom_byte_mask = 1;\n            }\n         }\n      }\n      while(rom_byte_number < 8);  // loop until through all ROM bytes 0-7\n\n      // if the search was successful then\n      if (!(id_bit_number < 65))\n      {\n         // search successful so set LastDiscrepancy,LastDeviceFlag,search_result\n         LastDiscrepancy[pin] = last_zero;\n\n         // check for last device\n         if (LastDiscrepancy[pin] == 0)\n            LastDeviceFlag[pin] = TRUE;\n\n         search_result = TRUE;\n      }\n   }\n\n   // if no device found then reset counters so next 'search' will be like a first\n   if (!search_result || !ROM_NO[pin][0])\n   {\n      LastDiscrepancy[pin] = 0;\n      LastDeviceFlag[pin] = FALSE;\n      LastFamilyDiscrepancy[pin] = 0;\n      search_result = FALSE;\n   }\n   int i;\n   for (i = 0; i < 8; i++) newAddr[i] = ROM_NO[pin][i];\n   return search_result;\n  }\n\n#endif\n\n\n#if ONEWIRE_CRC\n// The 1-Wire CRC scheme is described in Maxim Application Note 27:\n// \"Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products\"\n//\n\n#if ONEWIRE_CRC8_TABLE\n// This table comes from Dallas sample code where it is freely reusable,\n// though Copyright (C) 2000 Dallas Semiconductor Corporation\nstatic const uint8_t dscrc_table[] = {\n      0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,\n    157,195, 33,127,252,162, 64, 30, 95,  1,227,189, 62, 96,130,220,\n     35,125,159,193, 66, 28,254,160,225,191, 93,  3,128,222, 60, 98,\n    190,224,  2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,\n     70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89,  7,\n    219,133,103, 57,186,228,  6, 88, 25, 71,165,251,120, 38,196,154,\n    101, 59,217,135,  4, 90,184,230,167,249, 27, 69,198,152,122, 36,\n    248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91,  5,231,185,\n    140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,\n     17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,\n    175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,\n     50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,\n    202,148,118, 40,171,245, 23, 73,  8, 86,180,234,105, 55,213,139,\n     87,  9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,\n    233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,\n    116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};\n\n#ifndef pgm_read_byte\n#define pgm_read_byte(addr) (*(const uint8_t *)(addr))\n#endif\n\n//\n// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM\n// and the registers.  (note: this might better be done without to\n// table, it would probably be smaller and certainly fast enough\n// compared to all those delayMicrosecond() calls.  But I got\n// confused, so I use this table from the examples.)\n//\nuint8_t onewire_crc8(const uint8_t *addr, uint8_t len)\n{\n\tuint8_t crc = 0;\n\n\twhile (len--) {\n\t\tcrc = pgm_read_byte(dscrc_table + (crc ^ *addr++));\n\t}\n\treturn crc;\n}\n#else\n//\n// Compute a Dallas Semiconductor 8 bit CRC directly.\n// this is much slower, but much smaller, than the lookup table.\n//\nuint8_t onewire_crc8(const uint8_t *addr, uint8_t len)\n{\n\tuint8_t crc = 0;\n\t\n\twhile (len--) {\n\t\tuint8_t inbyte = *addr++;\n    uint8_t i;\n\t\tfor (i = 8; i; i--) {\n\t\t\tuint8_t mix = (crc ^ inbyte) & 0x01;\n\t\t\tcrc >>= 1;\n\t\t\tif (mix) crc ^= 0x8C;\n\t\t\tinbyte >>= 1;\n\t\t}\n\t}\n\treturn crc;\n}\n#endif\n\n#if ONEWIRE_CRC16\n// Compute the 1-Wire CRC16 and compare it against the received CRC.\n// Example usage (reading a DS2408):\n    //    // Put everything in a buffer so we can compute the CRC easily.\n//    uint8_t buf[13];\n//    buf[0] = 0xF0;    // Read PIO Registers\n//    buf[1] = 0x88;    // LSB address\n//    buf[2] = 0x00;    // MSB address\n//    WriteBytes(net, buf, 3);    // Write 3 cmd bytes\n//    ReadBytes(net, buf+3, 10);  // Read 6 data bytes, 2 0xFF, 2 CRC16\n//    if (!CheckCRC16(buf, 11, &buf[11])) {\n//        // Handle error.\n//    }     \n//          \n// @param input - Array of bytes to checksum.\n// @param len - How many bytes to use.\n// @param inverted_crc - The two CRC16 bytes in the received data.\n//                       This should just point into the received data,\n//                       *not* at a 16-bit integer.\n// @param crc - The crc starting value (optional)\n// @return True, iff the CRC matches.\nbool onewire_check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc)\n{\n    crc = ~onewire_crc16(input, len, crc);\n    return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1];\n}\n\n// Compute a Dallas Semiconductor 16 bit CRC.  This is required to check\n// the integrity of data received from many 1-Wire devices.  Note that the\n// CRC computed here is *not* what you'll get from the 1-Wire network,\n// for two reasons:\n//   1) The CRC is transmitted bitwise inverted.\n//   2) Depending on the endian-ness of your processor, the binary\n//      representation of the two-byte return value may have a different\n//      byte order than the two bytes you get from 1-Wire.\n// @param input - Array of bytes to checksum.\n// @param len - How many bytes to use.\n// @param crc - The crc starting value (optional)\n// @return The CRC16, as defined by Dallas Semiconductor.\nuint16_t onewire_crc16(const uint8_t* input, uint16_t len, uint16_t crc)\n{\n    static const uint8_t oddparity[16] =\n        { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };\n\n    uint16_t i;\n    for (i = 0 ; i < len ; i++) {\n      // Even though we're just copying a byte from the input,\n      // we'll be doing 16-bit computation with it.\n      uint16_t cdata = input[i];\n      cdata = (cdata ^ crc) & 0xff;\n      crc >>= 8;\n\n      if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4])\n          crc ^= 0xC001;\n\n      cdata <<= 6;\n      crc ^= cdata;\n      cdata <<= 1;\n      crc ^= cdata;\n    }\n    return crc;\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "app/driver/pwm.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: pwm.c\n *\n * Description: pwm driver\n *\n * Modification history:\n *     2014/5/1, v1.0 create this file.\n*******************************************************************************/\n#include \"platform.h\"\n\n#include \"ets_sys.h\"\n#include \"os_type.h\"\n#include \"osapi.h\"\n#include \"gpio.h\"\n\n#include \"user_interface.h\"\n#include \"driver/pwm.h\"\n\n// #define PWM_DBG os_printf\n#define PWM_DBG\n\nLOCAL struct pwm_single_param pwm_single_toggle[2][PWM_CHANNEL + 1];\nLOCAL struct pwm_single_param *pwm_single;\n\nLOCAL struct pwm_param pwm;\n\n// LOCAL uint8 pwm_out_io_num[PWM_CHANNEL] = {PWM_0_OUT_IO_NUM, PWM_1_OUT_IO_NUM, PWM_2_OUT_IO_NUM};\nLOCAL int8 pwm_out_io_num[PWM_CHANNEL] = {-1, -1, -1, -1, -1, -1};\n\nLOCAL uint8 pwm_channel_toggle[2];\nLOCAL uint8 *pwm_channel;\n\nLOCAL uint8 pwm_toggle = 1;\nLOCAL uint8 pwm_timer_down = 1;\n\nLOCAL uint8 pwm_current_channel = 0;\n\nLOCAL uint16 pwm_gpio = 0;\n\nLOCAL uint8 pwm_channel_num = 0;\n\n//XXX: 0xffffffff/(80000000/16)=35A\n#define US_TO_RTC_TIMER_TICKS(t)          \\\n    ((t) ?                                   \\\n     (((t) > 0x35A) ?                   \\\n      (((t)>>2) * ((APB_CLK_FREQ>>4)/250000) + ((t)&0x3) * ((APB_CLK_FREQ>>4)/1000000))  :    \\\n      (((t) *(APB_CLK_FREQ>>4)) / 1000000)) :    \\\n     0)\n\n//FRC1\n#define FRC1_ENABLE_TIMER  BIT7\n\ntypedef enum {\n    DIVDED_BY_1 = 0,\n    DIVDED_BY_16 = 4,\n    DIVDED_BY_256 = 8,\n} TIMER_PREDIVED_MODE;\n\ntypedef enum {\n    TM_LEVEL_INT = 1,\n    TM_EDGE_INT   = 0,\n} TIMER_INT_MODE;\n\nLOCAL void ICACHE_FLASH_ATTR\npwm_insert_sort(struct pwm_single_param pwm[], uint8 n)\n{\n    uint8 i;\n\n    for (i = 1; i < n; i++) {\n        if (pwm[i].h_time < pwm[i - 1].h_time) {\n            int8 j = i - 1;\n            struct pwm_single_param tmp;\n\n            os_memcpy(&tmp, &pwm[i], sizeof(struct pwm_single_param));\n            os_memcpy(&pwm[i], &pwm[i - 1], sizeof(struct pwm_single_param));\n\n            while (tmp.h_time < pwm[j].h_time) {\n                os_memcpy(&pwm[j + 1], &pwm[j], sizeof(struct pwm_single_param));\n                j--;\n                if (j < 0) {\n                \tbreak;\n                }\n            }\n\n            os_memcpy(&pwm[j + 1], &tmp, sizeof(struct pwm_single_param));\n        }\n    }\n}\n\nLOCAL volatile uint8 critical = 0;\n\n#define LOCK_PWM(c)  do {                       \\\n    while( (c)==1 );                            \\\n    (c) = 1;                                    \\\n} while (0)\n\n#define UNLOCK_PWM(c) do {                      \\\n    (c) = 0;                                    \\\n} while (0)\n\nvoid ICACHE_FLASH_ATTR\npwm_start(void)\n{\n    uint8 i, j;\n    PWM_DBG(\"--Function pwm_start() is called\\n\");\n    PWM_DBG(\"pwm_gpio:%x,pwm_channel_num:%d\\n\",pwm_gpio,pwm_channel_num);\n    PWM_DBG(\"pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\\n\",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);\n    PWM_DBG(\"pwm.period:%d,pwm.duty[0]:%d,[1]:%d,[2]:%d\\n\",pwm.period,pwm.duty[0],pwm.duty[1],pwm.duty[2]);\n\n    LOCK_PWM(critical);   // enter critical\n\n    struct pwm_single_param *local_single = pwm_single_toggle[pwm_toggle ^ 0x01];\n    uint8 *local_channel = &pwm_channel_toggle[pwm_toggle ^ 0x01];\n\n    // step 1: init PWM_CHANNEL+1 channels param\n    for (i = 0; i < pwm_channel_num; i++) {\n        uint32 us = pwm.period * pwm.duty[i] / PWM_DEPTH;\n        local_single[i].h_time = US_TO_RTC_TIMER_TICKS(us);\n        PWM_DBG(\"i:%d us:%d ht:%d\\n\",i,us,local_single[i].h_time);\n        local_single[i].gpio_set = 0;\n        local_single[i].gpio_clear = 1 << pin_num[pwm_out_io_num[i]];\n    }\n\n    local_single[pwm_channel_num].h_time = US_TO_RTC_TIMER_TICKS(pwm.period);\n    local_single[pwm_channel_num].gpio_set = pwm_gpio;\n    local_single[pwm_channel_num].gpio_clear = 0;\n    PWM_DBG(\"i:%d period:%d ht:%d\\n\",pwm_channel_num,pwm.period,local_single[pwm_channel_num].h_time);\n    // step 2: sort, small to big\n    pwm_insert_sort(local_single, pwm_channel_num + 1);\n\n    *local_channel = pwm_channel_num + 1;\n    PWM_DBG(\"1channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\\n\",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);\n    // step 3: combine same duty channels\n    for (i = pwm_channel_num; i > 0; i--) {\n        if (local_single[i].h_time == local_single[i - 1].h_time) {\n            local_single[i - 1].gpio_set |= local_single[i].gpio_set;\n            local_single[i - 1].gpio_clear |= local_single[i].gpio_clear;\n\n            for (j = i + 1; j < *local_channel; j++) {\n                os_memcpy(&local_single[j - 1], &local_single[j], sizeof(struct pwm_single_param));\n            }\n\n            (*local_channel)--;\n        }\n    }\n    PWM_DBG(\"2channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\\n\",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);\n    // step 4: cacl delt time\n    for (i = *local_channel - 1; i > 0; i--) {\n        local_single[i].h_time -= local_single[i - 1].h_time;\n    }\n\n    // step 5: last channel needs to clean\n    local_single[*local_channel-1].gpio_clear = 0;\n\n    // step 6: if first channel duty is 0, remove it\n    if (local_single[0].h_time == 0) {\n        local_single[*local_channel - 1].gpio_set &= ~local_single[0].gpio_clear;\n        local_single[*local_channel - 1].gpio_clear |= local_single[0].gpio_clear;\n\n        for (i = 1; i < *local_channel; i++) {\n            os_memcpy(&local_single[i - 1], &local_single[i], sizeof(struct pwm_single_param));\n        }\n\n        (*local_channel)--;\n    }\n\n    // if timer is down, need to set gpio and start timer\n    if (pwm_timer_down == 1) {\n        pwm_channel = local_channel;\n        pwm_single = local_single;\n        // start\n        gpio_output_set(local_single[0].gpio_set, local_single[0].gpio_clear, pwm_gpio, 0);\n\n        // yeah, if all channels' duty is 0 or 255, don't need to start timer, otherwise start...\n        if (*local_channel != 1) {\n            pwm_timer_down = 0;\n            RTC_REG_WRITE(FRC1_LOAD_ADDRESS, local_single[0].h_time);\n        }\n    }\n\n    if (pwm_toggle == 1) {\n        pwm_toggle = 0;\n    } else {\n        pwm_toggle = 1;\n    }\n\n    UNLOCK_PWM(critical);   // leave critical\n    PWM_DBG(\"3channel:%d,single[0]:%d,[1]:%d,[2]:%d,[3]:%d\\n\",*local_channel,local_single[0].h_time,local_single[1].h_time,local_single[2].h_time,local_single[3].h_time);\n}\n\n/******************************************************************************\n * FunctionName : pwm_set_duty\n * Description  : set each channel's duty params\n * Parameters   : uint8 duty    : 0 ~ PWM_DEPTH\n *                uint8 channel : channel index\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\npwm_set_duty(uint16 duty, uint8 channel)\n{\n    uint8 i;\n    for(i=0;i<pwm_channel_num;i++){\n        if(pwm_out_io_num[i] == channel){\n            channel = i;\n            break;\n        }\n    }\n    if(i==pwm_channel_num)      // non found\n        return;\n\n    LOCK_PWM(critical);   // enter critical\n    if (duty < 1) {\n        pwm.duty[channel] = 0;\n    } else if (duty >= PWM_DEPTH) {\n    \tpwm.duty[channel] = PWM_DEPTH;\n    } else {\n    \tpwm.duty[channel] = duty;\n    }\n    UNLOCK_PWM(critical);   // leave critical\n}\n\n/******************************************************************************\n * FunctionName : pwm_set_freq\n * Description  : set pwm frequency\n * Parameters   : uint16 freq : 100hz typically\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\npwm_set_freq(uint16 freq, uint8 channel)\n{\n    LOCK_PWM(critical);   // enter critical\n    if (freq > PWM_FREQ_MAX) {\n        pwm.freq = PWM_FREQ_MAX;\n    } else if (freq < 1) {\n        pwm.freq = 1;\n    } else {\n        pwm.freq = freq;\n    }\n\n    pwm.period = PWM_1S / pwm.freq;\n    UNLOCK_PWM(critical);   // leave critical\n}\n\n/******************************************************************************\n * FunctionName : pwm_set_freq_duty\n * Description  : set pwm frequency and each channel's duty\n * Parameters   : uint16 freq : 100hz typically\n *                uint16 *duty : each channel's duty\n * Returns      : NONE\n*******************************************************************************/\nLOCAL void ICACHE_FLASH_ATTR\npwm_set_freq_duty(uint16 freq, uint16 *duty)\n{\n    uint8 i;\n\n    pwm_set_freq(freq, 0);\n\n    for (i = 0; i < PWM_CHANNEL; i++) {\n        // pwm_set_duty(duty[i], i);\n        if(pwm_out_io_num[i] != -1)\n            pwm_set_duty(duty[i], pwm_out_io_num[i]);\n    }\n}\n\n/******************************************************************************\n * FunctionName : pwm_get_duty\n * Description  : get duty of each channel\n * Parameters   : uint8 channel : channel index\n * Returns      : NONE\n*******************************************************************************/\nuint16 ICACHE_FLASH_ATTR\npwm_get_duty(uint8 channel)\n{\n    uint8 i;\n    for(i=0;i<pwm_channel_num;i++){\n        if(pwm_out_io_num[i] == channel){\n            channel = i;\n            break;\n        }\n    }\n    if(i==pwm_channel_num)      // non found\n        return 0;\n\n    return pwm.duty[channel];\n}\n\n/******************************************************************************\n * FunctionName : pwm_get_freq\n * Description  : get pwm frequency\n * Parameters   : NONE\n * Returns      : uint16 : pwm frequency\n*******************************************************************************/\nuint16 ICACHE_FLASH_ATTR\npwm_get_freq(uint8 channel)\n{\n    return pwm.freq;\n}\n\n/******************************************************************************\n * FunctionName : pwm_period_timer\n * Description  : pwm period timer function, output high level,\n *                start each channel's high level timer\n * Parameters   : NONE\n * Returns      : NONE\n*******************************************************************************/\nLOCAL void ICACHE_RAM_ATTR\npwm_tim1_intr_handler(void)\n{\n    uint8 local_toggle = pwm_toggle;                        // pwm_toggle may change outside\n    RTC_CLR_REG_MASK(FRC1_INT_ADDRESS, FRC1_INT_CLR_MASK);\n\n    if (pwm_current_channel >= (*pwm_channel - 1)) {        // *pwm_channel may change outside\n        pwm_single = pwm_single_toggle[local_toggle];\n        pwm_channel = &pwm_channel_toggle[local_toggle];\n\n        gpio_output_set(pwm_single[*pwm_channel - 1].gpio_set,\n                        pwm_single[*pwm_channel - 1].gpio_clear,\n                        pwm_gpio,\n                        0);\n\n        pwm_current_channel = 0;\n\n        if (*pwm_channel != 1) {\n            RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time);\n        } else {\n            pwm_timer_down = 1;\n        }\n    } else {\n        gpio_output_set(pwm_single[pwm_current_channel].gpio_set,\n                        pwm_single[pwm_current_channel].gpio_clear,\n                        pwm_gpio, 0);\n\n        pwm_current_channel++;\n        RTC_REG_WRITE(FRC1_LOAD_ADDRESS, pwm_single[pwm_current_channel].h_time);\n    }\n}\n\n/******************************************************************************\n * FunctionName : pwm_init\n * Description  : pwm gpio, params and timer initialization\n * Parameters   : uint16 freq : pwm freq param\n *                uint16 *duty : each channel's duty\n * Returns      : NONE\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\npwm_init(uint16 freq, uint16 *duty)\n{\n    uint8 i;\n\n    RTC_REG_WRITE(FRC1_CTRL_ADDRESS,  //FRC2_AUTO_RELOAD|\n                  DIVDED_BY_16\n                  | FRC1_ENABLE_TIMER\n                  | TM_EDGE_INT);\n    RTC_REG_WRITE(FRC1_LOAD_ADDRESS, 0);\n\n    // PIN_FUNC_SELECT(PWM_0_OUT_IO_MUX, PWM_0_OUT_IO_FUNC);\n    // PIN_FUNC_SELECT(PWM_1_OUT_IO_MUX, PWM_1_OUT_IO_FUNC);\n    // PIN_FUNC_SELECT(PWM_2_OUT_IO_MUX, PWM_2_OUT_IO_FUNC);\n    // GPIO_OUTPUT_SET(GPIO_ID_PIN(PWM_0_OUT_IO_NUM), 0);\n    // GPIO_OUTPUT_SET(GPIO_ID_PIN(PWM_1_OUT_IO_NUM), 0);\n    // GPIO_OUTPUT_SET(GPIO_ID_PIN(PWM_2_OUT_IO_NUM), 0);\n    \n    for (i = 0; i < PWM_CHANNEL; i++) {\n        // pwm_gpio |= (1 << pwm_out_io_num[i]);\n        pwm_gpio = 0;\n        pwm.duty[0] = 0;\n    }\n\n    pwm_set_freq(500, 0);\n    // pwm_set_freq_duty(freq, duty);\n\n    pwm_start();\n    \n    ETS_FRC_TIMER1_INTR_ATTACH(pwm_tim1_intr_handler, NULL);\n    TM1_EDGE_INT_ENABLE();\n    ETS_FRC1_INTR_ENABLE();\n}\n\nbool ICACHE_FLASH_ATTR\npwm_add(uint8 channel){\n    PWM_DBG(\"--Function pwm_add() is called. channel:%d\\n\", channel);\n    PWM_DBG(\"pwm_gpio:%x,pwm_channel_num:%d\\n\",pwm_gpio,pwm_channel_num);\n    PWM_DBG(\"pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\\n\",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);\n    PWM_DBG(\"pwm.duty[0]:%d,[1]:%d,[2]:%d\\n\",pwm.duty[0],pwm.duty[1],pwm.duty[2]);\n    uint8 i;\n    for(i=0;i<PWM_CHANNEL;i++){\n        if(pwm_out_io_num[i]==channel)  // already exist\n            return true;\n        if(pwm_out_io_num[i] == -1){ // empty exist\n            LOCK_PWM(critical);   // enter critical\n            pwm_out_io_num[i] = channel;\n            pwm.duty[i] = 0;\n            pwm_gpio |= (1 << pin_num[channel]);\n            PIN_FUNC_SELECT(pin_mux[channel], pin_func[channel]);\n            GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[channel])), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[channel]))) & (~ GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); //disable open drain;\n            pwm_channel_num++;\n            UNLOCK_PWM(critical);   // leave critical\n            return true;\n        }\n    }\n    return false;\n}\n\nbool ICACHE_FLASH_ATTR\npwm_delete(uint8 channel){\n    PWM_DBG(\"--Function pwm_delete() is called. channel:%d\\n\", channel);\n    PWM_DBG(\"pwm_gpio:%x,pwm_channel_num:%d\\n\",pwm_gpio,pwm_channel_num);\n    PWM_DBG(\"pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\\n\",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);\n    PWM_DBG(\"pwm.duty[0]:%d,[1]:%d,[2]:%d\\n\",pwm.duty[0],pwm.duty[1],pwm.duty[2]);\n    uint8 i,j;\n    for(i=0;i<pwm_channel_num;i++){\n        if(pwm_out_io_num[i]==channel){  // exist\n            LOCK_PWM(critical);   // enter critical\n            pwm_out_io_num[i] = -1;\n            pwm_gpio &= ~(1 << pin_num[channel]);   //clear the bit\n            for(j=i;j<pwm_channel_num-1;j++){\n                pwm_out_io_num[j] = pwm_out_io_num[j+1];\n                pwm.duty[j] = pwm.duty[j+1];\n            }\n            pwm_out_io_num[pwm_channel_num-1] = -1;\n            pwm.duty[pwm_channel_num-1] = 0;\n            pwm_channel_num--;\n            UNLOCK_PWM(critical);   // leave critical\n            return true;\n        }\n    }\n    // non found\n    return true;\n}\n\nbool ICACHE_FLASH_ATTR\npwm_exist(uint8 channel){\n    PWM_DBG(\"--Function pwm_exist() is called. channel:%d\\n\", channel);\n    PWM_DBG(\"pwm_gpio:%x,pwm_channel_num:%d\\n\",pwm_gpio,pwm_channel_num);\n    PWM_DBG(\"pwm_out_io_num[0]:%d,[1]:%d,[2]:%d\\n\",pwm_out_io_num[0],pwm_out_io_num[1],pwm_out_io_num[2]);\n    PWM_DBG(\"pwm.duty[0]:%d,[1]:%d,[2]:%d\\n\",pwm.duty[0],pwm.duty[1],pwm.duty[2]);\n    uint8 i;\n    for(i=0;i<PWM_CHANNEL;i++){\n        if(pwm_out_io_num[i]==channel)  // exist\n            return true;\n    }\n    return false;\n}\n"
  },
  {
    "path": "app/driver/readline.c",
    "content": "#include \"ets_sys.h\"\n#include \"os_type.h\"\n#include \"osapi.h\"\n#include \"driver/uart.h\"\n#include \"c_types.h\"\n\nLOCAL os_timer_t readline_timer;\n\n// UartDev is defined and initialized in rom code.\nextern UartDevice UartDev;\n\n#define uart_putc uart0_putc\n\nbool uart_getc(char *c){\n    RcvMsgBuff *pRxBuff = &(UartDev.rcv_buff);\n    if(pRxBuff->pWritePos == pRxBuff->pReadPos){   // empty\n        return false;\n    }\n    // ETS_UART_INTR_DISABLE();\n    ETS_INTR_LOCK();\n    *c = (char)*(pRxBuff->pReadPos);\n    if (pRxBuff->pReadPos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) {\n        pRxBuff->pReadPos = pRxBuff->pRcvMsgBuff ; \n    } else {\n        pRxBuff->pReadPos++;\n    }\n    // ETS_UART_INTR_ENABLE();\n    ETS_INTR_UNLOCK();\n    return true;\n}\n\n#if 0\nint readline4lua(const char *prompt, char *buffer, int length){\n    char ch;\n    int line_position;\n\nstart:\n    /* show prompt */\n    uart0_sendStr(prompt);\n\n    line_position = 0;\n    os_memset(buffer, 0, length);\n    while (1)\n    {\n        while (uart_getc(&ch))\n        {\n            /* handle CR key */\n            if (ch == '\\r')\n            {\n                char next;\n                if (uart_getc(&next))\n                    ch = next;\n            }\n            /* backspace key */\n            else if (ch == 0x7f || ch == 0x08)\n            {\n                if (line_position > 0)\n                {\n                    uart_putc(0x08);\n                    uart_putc(' ');\n                    uart_putc(0x08);\n                    line_position--;\n                }\n                buffer[line_position] = 0;\n                continue;\n            }\n            /* EOF(ctrl+d) */\n            else if (ch == 0x04)\n            {\n                if (line_position == 0)\n                    /* No input which makes lua interpreter close */\n                    return 0;\n                else\n                    continue;\n            }\n            \n            /* end of line */\n            if (ch == '\\r' || ch == '\\n')\n            {\n                buffer[line_position] = 0;\n                uart_putc('\\n');\n                if (line_position == 0)\n                {\n                    /* Get a empty line, then go to get a new line */\n                    goto start;\n                }\n                else\n                {\n                    return line_position;\n                }\n            }\n\n            /* other control character or not an acsii character */\n            if (ch < 0x20 || ch >= 0x80)\n            {\n                continue;\n            }\n\n            /* echo */\n            uart_putc(ch);\n            buffer[line_position] = ch;\n            ch = 0;\n            line_position++;\n\n            /* it's a large line, discard it */\n            if (line_position >= length)\n                line_position = 0;\n       }\n    }\n}\n#endif\n"
  },
  {
    "path": "app/driver/relay.c",
    "content": "#include \"ets_sys.h\"\n#include \"os_type.h\"\n#include \"osapi.h\"\n#include \"mem.h\"\n#include \"c_types.h\"\n#include \"c_string.h\"\n#include \"c_stdlib.h\"\n#include \"c_stdio.h\"\n#include \"gpio.h\"\n#include \"user_interface.h\"\n#include \"user_config.h\"\n#include \"platform.h\"\n#include \"config.h\"\n#include \"driver/relay.h\"\n\n#define MAX_RELAY_LISTENERS 5\n\nuint8_t relay_init_ok=0;\n\nrelay_change_callback listeners[MAX_RELAY_LISTENERS];\n\nvoid ICACHE_FLASH_ATTR relay_register_listener(relay_change_callback f){\n\n\tNODE_DBG(\"Relay listener add %p\",f);\n\tint i=0;\n\twhile(listeners[i]!=NULL) i++;\n\n\tif(i>=MAX_RELAY_LISTENERS){\n\t\tNODE_DBG(\"No more listener space %d\",i);\n\t\treturn;\n\t}\n\n\tNODE_DBG(\"Relay listener add index %d\",i);\n\n\tlisteners[i]=f;\n}\n\nvoid ICACHE_FLASH_ATTR relay_unregister_listener(relay_change_callback f){\n\n\tNODE_DBG(\"Relay listener remove %p\",f);\n\n\tint i=0;\n\twhile(listeners[i]!=f) i++;\n\n\tif(i>=MAX_RELAY_LISTENERS)\n\t\treturn;\n\n\tlisteners[i]=NULL;\n}\n\nstatic void ICACHE_FLASH_ATTR relay_notify_listeners(int relayId,int state){\n\n\tNODE_DBG(\"relay_notify_listeners\");\n\n\tint i;\n\tfor(i=0;i<MAX_RELAY_LISTENERS;i++){\n\n\t\tif(listeners[i]!=NULL){\n\t\t\tNODE_DBG(\"Relay listener notify %p\",listeners[i]);\n\t\t\tlisteners[i](relayId,state);\n\t\t}\n\t}\n\n}\n\nstatic relay * ICACHE_FLASH_ATTR find_relay(int relayNumber){\n\n\t\n\n\tif(relayNumber>=RELAY_COUNT)\n\t\treturn NULL;\n\n\tconfig_data * config  = config_read();\n\n\treturn &config->relay_state.relay[relayNumber];\t\n\n}\n\nint ICACHE_FLASH_ATTR relay_get_state(int relayNumber){\n\n\trelay * r = find_relay(relayNumber);\n\tif(r==NULL)\n\t\treturn -1;\n\n\treturn r->state;\n\n}\n\nint ICACHE_FLASH_ATTR relay_set_state(int relayNumber,unsigned state){\n\n\trelay * r = find_relay(relayNumber);\n\tif(r==NULL)\n\t\treturn -1;\n\n\tr->state=state;\n\tplatform_gpio_write(r->gpioPin,r->state);\n\n\tconfig_save(NULL);\n\n\trelay_notify_listeners(relayNumber,state);\n\n\treturn r->state;\n}\n\nint ICACHE_FLASH_ATTR relay_toggle_state(int relayNumber){\n\n\trelay * r = find_relay(relayNumber);\n\tif(r==NULL)\n\t\treturn -1;\n\n\tr->state=!r->state;\n\n\tplatform_gpio_write(r->gpioPin,r->state);\n\n\tconfig_save(NULL);\n\n\trelay_notify_listeners(relayNumber,r->state);\n\n\treturn r->state;\n}\n\nvoid ICACHE_FLASH_ATTR relay_init(){\n\n\tif(relay_init_ok)\n\t\treturn;\n\t\n\trelay_init_ok=1;\n\n\tNODE_DBG(\"Relay init\");\n\n\t//zero listeners\n\tint i;\n\tfor(i=0;i<MAX_RELAY_LISTENERS;i++)\n\t\tlisteners[i]=NULL;\n\n\tconfig_data * config  = config_read();\n\n\tif(config->relay_state.init_ok){\n\n\t\t#ifdef DEVELOP_VERSION\n\t\t\tNODE_DBG(\"Relay init ok\");\n\t\t\tint j;\n\t\t\tfor(j=0;j<RELAY_COUNT;j++)\n\t\t\t\tNODE_DBG(\"\\tRelay #%d pin #%d state %d\",j,config->relay_state.relay[j].gpioPin,config->relay_state.relay[j].state);\n\n\t\t\t\tNODE_DBG(\"\");\n\t\t#endif\n\n\t\tint i;\n\t\tfor(i=0;i<RELAY_COUNT;i++)\n\t\t\tplatform_gpio_write(config->relay_state.relay[i].gpioPin,config->relay_state.relay[i].state);\n\n\t\treturn;\t\n\t}\n\n\n\t//relay #0 on pin 1\t\n\tconfig->relay_state.relay[0].gpioPin=1;\t\n\tconfig->relay_state.relay[0].state=0;\n\tplatform_gpio_mode(1,PLATFORM_GPIO_OUTPUT,PLATFORM_GPIO_FLOAT);     \n\n    //relay #1 on pin 2\n\tconfig->relay_state.relay[1].gpioPin=2;\t\n\tconfig->relay_state.relay[1].state=0;\n\tplatform_gpio_mode(2,PLATFORM_GPIO_OUTPUT,PLATFORM_GPIO_FLOAT);  \t\n\n    config->relay_state.init_ok=1;\n\n    config_save(config);\n}\n\nint ICACHE_FLASH_ATTR relay_count(){\n\n\treturn RELAY_COUNT;\n\n}"
  },
  {
    "path": "app/driver/spi.c",
    "content": "#include \"driver/spi.h\"\n\n\n/******************************************************************************\n * FunctionName : spi_lcd_mode_init\n * Description  : SPI master initial function for driving LCD TM035PDZV36\n * Parameters   : uint8 spi_no - SPI module number, Only \"SPI\" and \"HSPI\" are valid\n*******************************************************************************/\nvoid spi_lcd_mode_init(uint8 spi_no)\n{\n\tuint32 regvalue; \n\tif(spi_no>1) \t\treturn; //handle invalid input number\n\t//bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock\n\t//bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock\n\tif(spi_no==SPI){\n\t\tWRITE_PERI_REG(PERIPHS_IO_MUX, 0x005); //clear bit9,and bit8\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode\t\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode\t\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode\t\n\t}else if(spi_no==HSPI){\n\t\tWRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode\t\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode\t\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode\t\n\t}\t\t\t\n\n\tSET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND);\n\tCLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);\n\t// SPI clock=CPU clock/8\n\tWRITE_PERI_REG(SPI_CLOCK(spi_no), \n\t\t\t\t\t((1&SPI_CLKDIV_PRE)<<SPI_CLKDIV_PRE_S)|\n\t\t\t\t\t((3&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|\n\t\t\t\t\t((1&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|\n\t\t\t\t\t((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div\n\t\n}\n/******************************************************************************\n * FunctionName : spi_lcd_9bit_write\n * Description  : SPI 9bits transmission function for driving LCD TM035PDZV36\n * Parameters   : \tuint8 spi_no - SPI module number, Only \"SPI\" and \"HSPI\" are valid\n *\t\t\t\tuint8 high_bit - first high bit of the data, 0 is for \"0\",the other value 1-255 is for \"1\"\n *\t\t\t\tuint8 low_8bit- the rest 8bits of the data.\n*******************************************************************************/\nvoid spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit)\n{\n\tuint32 regvalue;\n\tuint8 bytetemp;\n\tif(spi_no>1) \t\treturn; //handle invalid input number\n\t\n\tif(high_bit)\t\tbytetemp=(low_8bit>>1)|0x80;\n\telse\t\t\t\tbytetemp=(low_8bit>>1)&0x7f;\n\t\n\tregvalue= ((8&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|((uint32)bytetemp);\t\t//configure transmission variable,9bit transmission length and first 8 command bit \n\tif(low_8bit&0x01) \tregvalue|=BIT15;        //write the 9th bit\n\twhile(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);\t\t//waiting for spi module available\n\tWRITE_PERI_REG(SPI_USER2(spi_no), regvalue);\t\t\t\t//write  command and command length into spi reg\n\tSET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);\t\t//transmission start\n}\n\n/******************************************************************************\n * FunctionName : spi_master_init\n * Description  : SPI master initial function for common byte units transmission\n * Parameters   : uint8 spi_no - SPI module number, Only \"SPI\" and \"HSPI\" are valid\n*******************************************************************************/\nvoid spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock)\n{\n\tuint32 regvalue; \n\n\tif(spi_no>1) \t\treturn; //handle invalid input number\n\n\tif(spi_no==SPI){\n\t\tWRITE_PERI_REG(PERIPHS_IO_MUX, 0x005); \n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode\t\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode\t\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode\t\n\t}\n\telse if(spi_no==HSPI){\n\t\tWRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); \n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode\t\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode\t\n\t\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode\t\n\t}\n\n\tSET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_DOUTDIN|SPI_USR_MOSI);\n\n    //set clock polarity\n    // TODO: This doesn't work\n    //if (cpol == 1) {\n    //    SET_PERI_REG_MASK(SPI_CTRL2(spi_no), (SPI_CK_OUT_HIGH_MODE<<SPI_CK_OUT_HIGH_MODE_S));\n    //} else {\n    //    SET_PERI_REG_MASK(SPI_CTRL2(spi_no), (SPI_CK_OUT_LOW_MODE<<SPI_CK_OUT_LOW_MODE_S));\n    //}\n    //os_printf(\"SPI_CTRL2 is %08x\\n\",READ_PERI_REG(SPI_CTRL2(spi_no)));\n\n    //set clock phase\n    if (cpha == 1) {\n    \tSET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE|SPI_CK_I_EDGE);\n    } else {\n    \tCLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_CK_OUT_EDGE|SPI_CK_I_EDGE);\n    }\n\n    CLEAR_PERI_REG_MASK(SPI_USER(HSPI), SPI_FLASH_MODE|SPI_WR_BYTE_ORDER|SPI_USR_MISO|\n                        SPI_RD_BYTE_ORDER|SPI_USR_ADDR|SPI_USR_COMMAND|SPI_USR_DUMMY);\n\n\t//clear Daul or Quad lines transmission mode\n\tCLEAR_PERI_REG_MASK(SPI_CTRL(spi_no), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE);\n\n\t// SPI clock=CPU clock/8\n\tWRITE_PERI_REG(SPI_CLOCK(spi_no), \n\t\t\t\t\t((1&SPI_CLKDIV_PRE)<<SPI_CLKDIV_PRE_S)|\n\t\t\t\t\t((3&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|\n\t\t\t\t\t((1&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|\n\t\t\t\t\t((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div\n\n\t//set 8bit output buffer length, the buffer is the low 8bit of register\"SPI_FLASH_C0\"\n\tWRITE_PERI_REG(SPI_USER1(spi_no), \n\t\t\t\t\t((7&SPI_USR_MOSI_BITLEN)<<SPI_USR_MOSI_BITLEN_S)|\n\t\t\t\t\t((7&SPI_USR_MISO_BITLEN)<<SPI_USR_MISO_BITLEN_S));\n}\n\n/******************************************************************************\n * FunctionName : spi_mast_byte_write\n * Description  : SPI master 1 byte transmission function\n * Parameters   : \tuint8 spi_no - SPI module number, Only \"SPI\" and \"HSPI\" are valid\n *\t\t\t\tuint8 data- transmitted data\n*******************************************************************************/\nvoid spi_mast_byte_write(uint8 spi_no, uint8 *data)\n{\n    if(spi_no>1) \t\treturn; //handle invalid input number\n\n    while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);\n\n    WRITE_PERI_REG(SPI_W0(spi_no), *data);\n\n    SET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);\n    while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);\n\n    *data = (uint8)(READ_PERI_REG(SPI_W0(spi_no))&0xff);\n}  \n\n/******************************************************************************\n * FunctionName : spi_byte_write_espslave\n * Description  : SPI master 1 byte transmission function for esp8266 slave,\n * \t\t\ttransmit 1byte data to esp8266 slave buffer needs 16bit transmission ,\n * \t\t\tfirst byte is command 0x04 to write slave buffer, second byte is data\n * Parameters   : \tuint8 spi_no - SPI module number, Only \"SPI\" and \"HSPI\" are valid\n *\t\t\t\tuint8 data- transmitted data\n*******************************************************************************/\nvoid spi_byte_write_espslave(uint8 spi_no,uint8 data)\n {\n\tuint32 regvalue;\n\n\tif(spi_no>1) \t\treturn; //handle invalid input number\n\n\twhile(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);\n\tSET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI);\n\tCLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO|SPI_USR_ADDR|SPI_USR_DUMMY);\n\n\t//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,\n\t// bit15-0 is cmd value.\n\t//0x70000000 is for 8bits cmd, 0x04 is eps8266 slave write cmd value\n\tWRITE_PERI_REG(SPI_USER2(spi_no), \n\t\t\t\t\t((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|4);\n\tWRITE_PERI_REG(SPI_W0(spi_no), (uint32)(data));\n\tSET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);\n }\n/******************************************************************************\n * FunctionName : spi_byte_read_espslave\n * Description  : SPI master 1 byte read function for esp8266 slave,\n * \t\t\tread 1byte data from esp8266 slave buffer needs 16bit transmission ,\n * \t\t\tfirst byte is command 0x06 to read slave buffer, second byte is recieved data\n * Parameters   : \tuint8 spi_no - SPI module number, Only \"SPI\" and \"HSPI\" are valid\n *\t\t\t\tuint8* data- recieved data address\n*******************************************************************************/\n  void spi_byte_read_espslave(uint8 spi_no,uint8 *data)\n {\n\tuint32 regvalue;\n\n\tif(spi_no>1) \t\treturn; //handle invalid input number\n\n\twhile(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);\n\n\tSET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MISO);\n\tCLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_MOSI|SPI_USR_ADDR|SPI_USR_DUMMY);\n\t\t//SPI_FLASH_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,\n\t// bit15-0 is cmd value.\n\t//0x70000000 is for 8bits cmd, 0x06 is eps8266 slave read cmd value\n\tWRITE_PERI_REG(SPI_USER2(spi_no), \n\t\t\t\t\t((7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S)|6);\n\tSET_PERI_REG_MASK(SPI_CMD(spi_no), SPI_USR);\n\t\n\twhile(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);\n\t*data=(uint8)(READ_PERI_REG(SPI_W0(spi_no))&0xff);\n }\n\n/******************************************************************************\n * FunctionName : spi_slave_init\n * Description  : SPI slave mode initial funtion, including mode setting,\n * \t\t\tIO setting, transmission interrupt opening, interrupt function registration\n * Parameters   : \tuint8 spi_no - SPI module number, Only \"SPI\" and \"HSPI\" are valid\n*******************************************************************************/\nvoid spi_slave_init(uint8 spi_no)\n{\n    uint32 regvalue; \n    if(spi_no>1)\n        return; //handle invalid input number\n\n    //clear bit9,bit8 of reg PERIPHS_IO_MUX\n    //bit9 should be cleared when HSPI clock doesn't equal CPU clock\n    //bit8 should be cleared when SPI clock doesn't equal CPU clock\n    ////WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9//TEST\n    if(spi_no==SPI){\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CLK_U, 1);//configure io to spi mode\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_CMD_U, 1);//configure io to spi mode\t\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA0_U, 1);//configure io to spi mode\t\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_SD_DATA1_U, 1);//configure io to spi mode\t\n    }else if(spi_no==HSPI){\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure io to spi mode\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure io to spi mode\t\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure io to spi mode\t\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure io to spi mode\t\n    }\n\n    //regvalue=READ_PERI_REG(SPI_FLASH_SLAVE(spi_no));\n    //slave mode,slave use buffers which are register \"SPI_FLASH_C0~C15\", enable trans done isr\n    //set bit 30 bit 29 bit9,bit9 is trans done isr mask\n    SET_PERI_REG_MASK(\tSPI_SLAVE(spi_no), \n    \t\t\t\t\t\tSPI_SLAVE_MODE|SPI_SLV_WR_RD_BUF_EN|\n                                         \tSPI_SLV_WR_BUF_DONE_EN|SPI_SLV_RD_BUF_DONE_EN|\n                                         \tSPI_SLV_WR_STA_DONE_EN|SPI_SLV_RD_STA_DONE_EN|\n                                         \tSPI_TRANS_DONE_EN);\n    //disable general trans intr \n    //CLEAR_PERI_REG_MASK(SPI_SLAVE(spi_no),SPI_TRANS_DONE_EN);\n\n    CLEAR_PERI_REG_MASK(SPI_USER(spi_no), SPI_FLASH_MODE);//disable flash operation mode\n    SET_PERI_REG_MASK(SPI_USER(spi_no),SPI_USR_MISO_HIGHPART);//SLAVE SEND DATA BUFFER IN C8-C15 \n\n\n//////**************RUN WHEN SLAVE RECIEVE*******************///////\n   //tow lines below is to configure spi timing.\n    SET_PERI_REG_MASK(SPI_CTRL2(spi_no),(0x2&SPI_MOSI_DELAY_NUM)<<SPI_MOSI_DELAY_NUM_S) ;//delay num\n    os_printf(\"SPI_CTRL2 is %08x\\n\",READ_PERI_REG(SPI_CTRL2(spi_no)));\n    WRITE_PERI_REG(SPI_CLOCK(spi_no), 0);\n\n\n    \n/////***************************************************//////\t\n\n    //set 8 bit slave command length, because slave must have at least one bit addr, \n    //8 bit slave+8bit addr, so master device first 2 bytes can be regarded as a command \n    //and the  following bytes are datas, \n    //32 bytes input wil be stored in SPI_FLASH_C0-C7\n    //32 bytes output data should be set to SPI_FLASH_C8-C15\n    WRITE_PERI_REG(SPI_USER2(spi_no), (0x7&SPI_USR_COMMAND_BITLEN)<<SPI_USR_COMMAND_BITLEN_S); //0x70000000\n\n    //set 8 bit slave recieve buffer length, the buffer is SPI_FLASH_C0-C7\n    //set 8 bit slave status register, which is the low 8 bit of register \"SPI_FLASH_STATUS\"\n    SET_PERI_REG_MASK(SPI_SLAVE1(spi_no),  ((0xff&SPI_SLV_BUF_BITLEN)<< SPI_SLV_BUF_BITLEN_S)|\n                                                                                        ((0x7&SPI_SLV_STATUS_BITLEN)<<SPI_SLV_STATUS_BITLEN_S)|\n                                                                                       ((0x7&SPI_SLV_WR_ADDR_BITLEN)<<SPI_SLV_WR_ADDR_BITLEN_S)|\n                                                                                       ((0x7&SPI_SLV_RD_ADDR_BITLEN)<<SPI_SLV_RD_ADDR_BITLEN_S));\n    \n    SET_PERI_REG_MASK(SPI_PIN(spi_no),BIT19);//BIT19   \n\n    //maybe enable slave transmission liston \n    SET_PERI_REG_MASK(SPI_CMD(spi_no),SPI_USR);\n    //register level2 isr function, which contains spi, hspi and i2s events\n    ETS_SPI_INTR_ATTACH(spi_slave_isr_handler,NULL);\n    //enable level2 isr, which contains spi, hspi and i2s events\n    ETS_SPI_INTR_ENABLE(); \n}\n\n\n\n\n\n/* =============================================================================================\n * code below is for spi slave r/w testcase with 2 r/w state lines connected to the spi master mcu\n * replace with your own process functions\n * find \"add system_os_post here\" in spi_slave_isr_handler.\n * =============================================================================================\n */\n\n\n\n\n\n\n\n#ifdef SPI_SLAVE_DEBUG\n /******************************************************************************\n * FunctionName : hspi_master_readwrite_repeat\n * Description  : SPI master test  function for reading and writing esp8266 slave buffer,\n \t\t\tthe function uses HSPI module \n*******************************************************************************/\nos_timer_t timer2;\n\nvoid hspi_master_readwrite_repeat(void)\n{\n\tstatic uint8 data=0;\n\tuint8 temp;\n\n\tos_timer_disarm(&timer2);\n\tspi_byte_read_espslave(HSPI,&temp);\n\n\ttemp++;\n\tspi_byte_write_espslave(HSPI,temp);\n       os_timer_setfn(&timer2, (os_timer_func_t *)hspi_master_readwrite_repeat, NULL);\n       os_timer_arm(&timer2, 500, 0);\n}\n#endif\n\n\n/******************************************************************************\n * FunctionName : spi_slave_isr_handler\n * Description  : SPI interrupt function, SPI HSPI and I2S interrupt can trig this function\n \t\t\t   some basic operation like clear isr flag has been done, \n \t\t\t   and it is availible\tfor adding user coder in the funtion\n * Parameters  : void *para- function parameter address, which has been registered in function spi_slave_init\n*******************************************************************************/\n#include \"gpio.h\"\n#include \"user_interface.h\"\n#include \"mem.h\"\nstatic uint8 spi_data[32] = {0};\nstatic uint8 idx = 0;\nstatic uint8 spi_flg = 0;\n#define SPI_MISO\n#define SPI_QUEUE_LEN 8\nos_event_t * spiQueue;\n#define MOSI  0\n#define MISO  1\n#define STATUS_R_IN_WR 2\n#define STATUS_W  3\n#define TR_DONE_ALONE  4\n#define WR_RD 5\n#define DATA_ERROR 6\n#define STATUS_R_IN_RD 7\n//init the two intr line of slave\n//gpio0: wr_ready ,and  \n//gpio2: rd_ready , controlled by slave\nvoid ICACHE_FLASH_ATTR\n    gpio_init()\n{\n\n    \tPIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);\n\tPIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);\n\t//PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);\n    \tGPIO_OUTPUT_SET(0, 1);\n    \tGPIO_OUTPUT_SET(2, 0);\n\t//GPIO_OUTPUT_SET(4, 1);\n}\n\n\n\nvoid spi_slave_isr_handler(void *para)\n{\n\tuint32 regvalue,calvalue;\n    \tstatic uint8 state =0;\n\tuint32 recv_data,send_data;\n\n\tif(READ_PERI_REG(0x3ff00020)&BIT4){\t\t\n        //following 3 lines is to clear isr signal\n        \tCLEAR_PERI_REG_MASK(SPI_SLAVE(SPI), 0x3ff);\n    \t}else if(READ_PERI_REG(0x3ff00020)&BIT7){ //bit7 is for hspi isr,\n        \tregvalue=READ_PERI_REG(SPI_SLAVE(HSPI));\n         \tCLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),  \n\t\t\t\t\t\t\t\tSPI_TRANS_DONE_EN|\n\t\t\t\t\t\t\t\tSPI_SLV_WR_STA_DONE_EN|\n\t\t\t\t\t\t\t\tSPI_SLV_RD_STA_DONE_EN|\n\t\t\t\t\t\t\t\tSPI_SLV_WR_BUF_DONE_EN|\n\t\t\t\t\t\t\t\tSPI_SLV_RD_BUF_DONE_EN);\n        \tSET_PERI_REG_MASK(SPI_SLAVE(HSPI), SPI_SYNC_RESET);\n        \tCLEAR_PERI_REG_MASK(SPI_SLAVE(HSPI),  \n\t\t\t\t\t\t\t\tSPI_TRANS_DONE|\n\t\t\t\t\t\t\t\tSPI_SLV_WR_STA_DONE|\n\t\t\t\t\t\t\t\tSPI_SLV_RD_STA_DONE|\n\t\t\t\t\t\t\t\tSPI_SLV_WR_BUF_DONE|\n\t\t\t\t\t\t\t\tSPI_SLV_RD_BUF_DONE); \n\t\tSET_PERI_REG_MASK(SPI_SLAVE(HSPI),  \n\t\t\t\t\t\t\t\tSPI_TRANS_DONE_EN|\n\t\t\t\t\t\t\t\tSPI_SLV_WR_STA_DONE_EN|\n\t\t\t\t\t\t\t\tSPI_SLV_RD_STA_DONE_EN|\n\t\t\t\t\t\t\t\tSPI_SLV_WR_BUF_DONE_EN|\n\t\t\t\t\t\t\t\tSPI_SLV_RD_BUF_DONE_EN);\n\n\t\tif(regvalue&SPI_SLV_WR_BUF_DONE){ \n            \t\tGPIO_OUTPUT_SET(0, 0);\n            \t\tidx=0;\n            \t\twhile(idx<8){\n            \t\t\trecv_data=READ_PERI_REG(SPI_W0(HSPI)+(idx<<2));\n            \t\t\tspi_data[idx<<2] = recv_data&0xff;\n            \t\t\tspi_data[(idx<<2)+1] = (recv_data>>8)&0xff;\n            \t\t\tspi_data[(idx<<2)+2] = (recv_data>>16)&0xff;\n            \t\t\tspi_data[(idx<<2)+3] = (recv_data>>24)&0xff;\n            \t\t\tidx++;\n\t\t\t}\n\t\t\t//add system_os_post here\n            \t\tGPIO_OUTPUT_SET(0, 1);\n\t\t}\n        \tif(regvalue&SPI_SLV_RD_BUF_DONE){\n\t\t\t//it is necessary to call GPIO_OUTPUT_SET(2, 1), when new data is preped in SPI_W8-15 and needs to be sended.\n           \t\tGPIO_OUTPUT_SET(2, 0);\n\t\t\t//add system_os_post here\n\t\t\t//system_os_post(USER_TASK_PRIO_1,WR_RD,regvalue);\n\n        \t}\n    \n    }else if(READ_PERI_REG(0x3ff00020)&BIT9){ //bit7 is for i2s isr,\n\n    }\n}\n\n\n#ifdef SPI_SLAVE_DEBUG\n\nvoid ICACHE_FLASH_ATTR\n    set_miso_data()\n{\n    if(GPIO_INPUT_GET(2)==0){\n        WRITE_PERI_REG(SPI_W8(HSPI),0x05040302);\n        WRITE_PERI_REG(SPI_W9(HSPI),0x09080706);\n        WRITE_PERI_REG(SPI_W10(HSPI),0x0d0c0b0a);\n        WRITE_PERI_REG(SPI_W11(HSPI),0x11100f0e);\n\n        WRITE_PERI_REG(SPI_W12(HSPI),0x15141312);\n        WRITE_PERI_REG(SPI_W13(HSPI),0x19181716);\n        WRITE_PERI_REG(SPI_W14(HSPI),0x1d1c1b1a);\n        WRITE_PERI_REG(SPI_W15(HSPI),0x21201f1e);\n        GPIO_OUTPUT_SET(2, 1);\n    }\n}\n\n\n\nvoid ICACHE_FLASH_ATTR\n    disp_spi_data()\n{\n    uint8 i = 0;\n    for(i=0;i<32;i++){\n        os_printf(\"data %d : 0x%02x\\n\\r\",i,spi_data[i]);\n    }\n    //os_printf(\"d31:0x%02x\\n\\r\",spi_data[31]);\n}\n\n\nvoid ICACHE_FLASH_ATTR\n    spi_task(os_event_t *e)\n{\n    uint8 data;\n    switch(e->sig){\n       case MOSI:\n            \tdisp_spi_data();\n            \tbreak;\n\tcase STATUS_R_IN_WR :\n\t\tos_printf(\"SR ERR in WRPR,Reg:%08x \\n\",e->par);\n\t\tbreak;\n\tcase STATUS_W:\n\t\tos_printf(\"SW ERR,Reg:%08x\\n\",e->par);\n\t\tbreak;\t\n\tcase TR_DONE_ALONE:\n\t\tos_printf(\"TD ALO ERR,Reg:%08x\\n\",e->par);\n\t\tbreak;\t\n\tcase WR_RD:\n\t\tos_printf(\"WR&RD ERR,Reg:%08x\\n\",e->par);\n\t\tbreak;\t\n\tcase DATA_ERROR:\n\t\tos_printf(\"Data ERR,Reg:%08x\\n\",e->par);\n\t\tbreak;\n\tcase STATUS_R_IN_RD :\n\t\tos_printf(\"SR ERR in RDPR,Reg:%08x\\n\",e->par);\n\t\tbreak;\t\n        default:\n            break;\n    }\n}\n\nvoid ICACHE_FLASH_ATTR\n    spi_task_init(void)\n{\n    spiQueue = (os_event_t*)os_malloc(sizeof(os_event_t)*SPI_QUEUE_LEN);\n    system_os_task(spi_task,USER_TASK_PRIO_1,spiQueue,SPI_QUEUE_LEN);\n}\n\nos_timer_t spi_timer_test;\n\nvoid ICACHE_FLASH_ATTR\n    spi_test_init()\n{\n    os_printf(\"spi init\\n\\r\");\n    spi_slave_init(HSPI);\n    os_printf(\"gpio init\\n\\r\");\n    gpio_init();\n    os_printf(\"spi task init \\n\\r\");\n    spi_task_init();\n#ifdef SPI_MISO\n    os_printf(\"spi miso init\\n\\r\");\n    set_miso_data();\n#endif\n    \n    //os_timer_disarm(&spi_timer_test);\n    //os_timer_setfn(&spi_timer_test, (os_timer_func_t *)set_miso_data, NULL);//wjl\n    //os_timer_arm(&spi_timer_test,50,1);\n}\n\n#endif\n\n\n"
  },
  {
    "path": "app/driver/uart_interrupt.c",
    "content": "#include \"ets_sys.h\"\n#include \"osapi.h\"\n#include \"driver/uart.h\"\n#include \"osapi.h\"\n#include \"driver/uart_register.h\"\n#include \"user_config.h\"\n#include \"mem.h\"\n#include \"os_type.h\"\n#include \"util/linked_list.h\"\n\n// UartDev is defined and initialized in rom code.\nextern UartDevice UartDev;\n\n#define UART_RX_INTR_DISABLE(uart) CLEAR_PERI_REG_MASK(UART_INT_ENA(uart), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA)\n#define UART_RX_INTR_ENABLE(uart) SET_PERI_REG_MASK(UART_INT_ENA(uart), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA)\n#define UART_TX_INTR_DISABLE(uart) CLEAR_PERI_REG_MASK(UART_INT_ENA(uart), UART_TXFIFO_EMPTY_INT_ENA)\n#define UART_TX_INTR_ENABLE(uart) SET_PERI_REG_MASK(UART_CONF1(uart), (UART_TX_EMPTY_THRESH_VAL & UART_TXFIFO_EMPTY_THRHD)<<UART_TXFIFO_EMPTY_THRHD_S);\t\\\n    \t\t\t\t\t\t   SET_PERI_REG_MASK(UART_INT_ENA(uart), UART_TXFIFO_EMPTY_INT_ENA)\n\n#define UART_RESET_FIFO(uart) SET_PERI_REG_MASK(UART_CONF0(uart), UART_RXFIFO_RST | UART_TXFIFO_RST);\t\\\n    \t\t\t\t\t   CLEAR_PERI_REG_MASK(UART_CONF0(uart), UART_RXFIFO_RST | UART_TXFIFO_RST)\n\n#define UART_CLEAR_ALL_INTR(uart) WRITE_PERI_REG(UART_INT_CLR(uart), 0xffff)\n#define UART_CLEAR_INTR(uart,INTERRUPT) WRITE_PERI_REG(UART_INT_CLR(uart), INTERRUPT)\n#define UART_INTERRUPT_IS(uart,INTERRUPT) INTERRUPT == (READ_PERI_REG(UART_INT_ST(uart)) & INTERRUPT)\n\n#define UART_RX_FIFO_COUNT(uart) (READ_PERI_REG(UART_STATUS(uart))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT\n#define UART_TX_FIFO_COUNT(uart) (READ_PERI_REG(UART_STATUS(uart))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT\n\n#define UART0_READ_CHAR() READ_PERI_REG(UART_FIFO(UART0)) & 0xFF\n#define UART_WRITE_CHAR(uart,c) WRITE_PERI_REG(UART_FIFO(uart), c)\n\nstatic uart0_data_received_callback_t uart0_data_received_callback=NULL;\n\nLOCAL void uart_rx_intr_handler(void *para);\n\nLOCAL void uart_transmit(uint8_t uart);\n\n#define TX_ITEM_LEN 128\n\nstruct tx_item{\n\tuint8_t data[TX_ITEM_LEN];\n\tint len;\n};\n\nlinked_list tx_list[2];\nos_timer_t tx_timer[2];\n\n//UART TRANSMIT ------------------------------------------------------------\nSTATUS uart_tx_one_char(uint8_t uart, uint8_t TxChar)\n{\n    while (true){\n        uint8_t fifo_cnt = UART_TX_FIFO_COUNT(uart);\n        if (fifo_cnt < 126) {\n            break;\n        }\n    }\n    UART_WRITE_CHAR(uart,TxChar);\n    return OK;\n}\n\nSTATUS uart_tx_one_char_no_wait(uint8_t uart, uint8_t TxChar)\n{\n    uint8_t fifo_cnt = UART_TX_FIFO_COUNT(uart);\n    if (fifo_cnt < 126) {\n        UART_WRITE_CHAR(uart,TxChar);\n    }\n    return OK;\n}\n\nstatic void tx_timer_timeout(void *arg){\n\n\t//NODE_DBG(\"u tout\");\n\n\tif(arg==(void*)0){\n\t\tuart_transmit(0);\n\t}\n\telse{\n\t\tuart_transmit(1);\n\t}\n\n}\n\nvoid uart_write(uint8_t uart,uint8_t *data,int len){\n\n\tlinked_list *list = &tx_list[uart];\n\n\tuint8_t fifo_cnt = UART_TX_FIFO_COUNT(uart);\n    if (fifo_cnt > len && list->size==0) { \n    \t//we can write on uart buffer\n    \twhile(len>0){\n    \t\tUART_WRITE_CHAR(uart,*data);\n    \t\tdata++;\n    \t\tlen--;\n    \t}\n        \n        return;\n    }\n\n    //if fifo is full, buffer on our own\t\n\t\t\n\twhile(len>0){\n\n\t\tstruct tx_item *tx = (struct tx_item *)list_get_first(list);\n\n\t\tif(tx==NULL || tx->len >= TX_ITEM_LEN){\n\t\t\ttx = (struct tx_item*)os_zalloc(sizeof(struct tx_item));\n\t\t\tlist_add_first(list,tx);\n\t\t}\n\n\t\tint remLen = TX_ITEM_LEN-tx->len;\n\t\tif(len <= remLen){\n\t\t\tos_memcpy(tx->data+tx->len,data,len);\n\t\t\ttx->len+=len;\n\t\t\tlen=0;\n\t\t}\n\t\telse{\n\t\t\tos_memcpy(tx->data+tx->len,data,remLen);\n\t\t\ttx->len+=remLen;\n\t\t\tlen-=remLen;\n\t\t\tdata+=remLen;\n\t\t}\n\t\t\t\t\n\t}\n\t\n\tos_timer_disarm(&tx_timer[uart]);\n\tos_timer_arm(&tx_timer[uart], 20, 0);\n}\n\nvoid uart_write_char(uint8_t uart,char c){\n\tuart_write(uart,&c,1);\t\t\n}\n\nvoid uart_write_string(uint8_t uart,const char *s){\n\tint str_len = os_strlen(s);\n\tuart_write(uart,(uint8_t*)s,str_len);\n}\n\n\nvoid ICACHE_FLASH_ATTR uart_config(uint8_t uart_no)\n{\n    if (uart_no == UART1){\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);\n    }else{\n        /* rcv_buff size if 0x100 */\n        ETS_UART_INTR_ATTACH(uart_rx_intr_handler,  &(UartDev.rcv_buff));\n        PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);\n        PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);\n\t\t#if UART_HW_RTS\n\t\t    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);   //HW FLOW CONTROL RTS PIN\n\t\t    #endif\n\t\t#if UART_HW_CTS\n\t\t    PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_U0CTS);   //HW FLOW CONTROL CTS PIN\n\t\t#endif\n    }\n    uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));//SET BAUDRATE\n    \n    WRITE_PERI_REG(UART_CONF0(uart_no), ((UartDev.exist_parity & UART_PARITY_EN_M)  <<  UART_PARITY_EN_S) //SET BIT AND PARITY MODE\n                                                                        | ((UartDev.parity & UART_PARITY_M)  <<UART_PARITY_S )\n                                                                        | ((UartDev.stop_bits & UART_STOP_BIT_NUM) << UART_STOP_BIT_NUM_S)\n                                                                        | ((UartDev.data_bits & UART_BIT_NUM) << UART_BIT_NUM_S));\n    \n    //clear rx and tx fifo,not ready\n    UART_RESET_FIFO(uart_no);\n    \n    if (uart_no == UART0){\n        //set rx fifo trigger\n        WRITE_PERI_REG(UART_CONF1(uart_no),\n        ((100 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |\n        #if UART_HW_RTS\n\t        ((110 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |\n\t        UART_RX_FLOW_EN |   //enbale rx flow control\n        #endif\n\t        (0x60 & UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S |\n\t        UART_RX_TOUT_EN|\n        ((0x10 & UART_TXFIFO_EMPTY_THRHD)<<UART_TXFIFO_EMPTY_THRHD_S));//wjl \n        #if UART_HW_CTS\n        \tSET_PERI_REG_MASK( UART_CONF0(uart_no),UART_TX_FLOW_EN);  //add this sentense to add a tx flow control via MTCK( CTS )\n        #endif\n        SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_TOUT_INT_ENA |UART_FRM_ERR_INT_ENA);\n    }else{\n        WRITE_PERI_REG(UART_CONF1(uart_no),((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));//TrigLvl default val == 1\n    }\n    //clear all interrupt\n    WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);\n    //enable rx_interrupt\n    SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_OVF_INT_ENA);\n}\n \nLOCAL void uart_transmit(uint8_t uart){\n\n\t\n\tuint8_t tx_fifo_len;\n\tuint8_t fifo_remain;\n\n\tlinked_list *list = &tx_list[uart];\n\n\tstruct tx_item *item=NULL;\n\nprocess:\n\ttx_fifo_len = UART_TX_FIFO_COUNT(uart);\n\tfifo_remain = UART_FIFO_LEN - tx_fifo_len ;\n\titem = (struct tx_item *)list_remove_last(list);\n\n\tif(item!=NULL){\n\n\t\tint i;\n\t\tint tx_count = item->len > fifo_remain?fifo_remain:item->len;\n\n\t\tif(fifo_remain >= item->len){\n\t\t\tfor(i = 0; i<item->len;i++)\n        \t\tUART_WRITE_CHAR(uart,item->data[i]);\n\n        \tos_free(item);\n        \tgoto process;\n\t\t}\n\t\telse{\n\t\t\tfor(i=0;i<fifo_remain;i++)\n\t\t\t\tUART_WRITE_CHAR(uart,item->data[i]);\n\n\t\t\tos_memmove(item->data, item->data+fifo_remain, item->len - fifo_remain);\n\t\t\titem->len -= fifo_remain;\n\t\t\tlist_add_last(list,item); //put back on list\t\t\t\n\t\t}\n\n        if(tx_list->size>0)\n\t\t\tUART_TX_INTR_ENABLE(uart); //enable interrupt so we may send data again\n\n\t\t\n\t}\t\n\n}\n\nLOCAL void uart0_data_received(){\n\n\tuint8_t data_len = UART_RX_FIFO_COUNT(0);\n\t\n\tif(data_len<=0)\n\t\treturn;\n\n\tif(uart0_data_received_callback!=NULL){\n\n\t\tuint8_t *tmp_data = (uint8_t*)os_malloc(data_len);\n\t\tint i;\n\t\tuint8_t c;\n\t\tfor(i=0;i<data_len;i++){\n\t\t\tc = UART0_READ_CHAR();\n\t\t\t\n\t\t\ttmp_data[i]=c;\n\t\t}\n\n\t\tuart0_data_received_callback(tmp_data,data_len);\n\t\tos_free(tmp_data);\n\n\t}\n\n}\n\nLOCAL void uart_rx_intr_handler(void *para)\n{    \n\n\tif( UART_INTERRUPT_IS(0,UART_FRM_ERR_INT_ST) ){\n\t\t//just clear intr\n\t\tUART_CLEAR_INTR(0,UART_FRM_ERR_INT_CLR);\n\t\treturn;\n\t}\n\tif( UART_INTERRUPT_IS(1,UART_FRM_ERR_INT_ST) ){\n\t\t//just clear intr\n\t\tUART_CLEAR_INTR(1,UART_FRM_ERR_INT_CLR);\n\t\treturn;\n\t}\n\n\n\t\n\tif( UART_INTERRUPT_IS(0,UART_RXFIFO_FULL_INT_ST) ){\n\t\t\n\t\t//got data on rx fifo\n\t\tUART_RX_INTR_DISABLE(0); //disable rx interrupt\n\n\t\tuart0_data_received();\n\n\t\tUART_CLEAR_INTR(0,UART_RXFIFO_FULL_INT_CLR); //clear interrupt\n\t\tUART_RX_INTR_ENABLE(0); //enable interrupt back\n\t\treturn;\n\t}\n\t\n\tif( UART_INTERRUPT_IS(0,UART_RXFIFO_TOUT_INT_ST) ){\n\t\t\n\t\t//got data on uart 0 rx fifo, timeout for fifo full\n\t\tUART_RX_INTR_DISABLE(0); //disable rx interrupt\n\n\t\tuart0_data_received();\n\n\t\tUART_CLEAR_INTR(0,UART_RXFIFO_TOUT_INT_CLR); //clear interrupt\n\t\tUART_RX_INTR_ENABLE(0); //enable interrupt back\n\t\treturn;\n\t}\n\n\tif( UART_INTERRUPT_IS(0,UART_TXFIFO_EMPTY_INT_ST) ){\n\n\t\tUART_TX_INTR_DISABLE(0);\n\n\t\tuart_transmit(0);\n\n\t\tUART_CLEAR_INTR(0,UART_TXFIFO_EMPTY_INT_CLR); //clear interrupt\n\t\treturn;\n\t}\n\n\tif( UART_INTERRUPT_IS(1,UART_TXFIFO_EMPTY_INT_ST) ){\n\n\t\tUART_TX_INTR_DISABLE(1);\n\n\t\tuart_transmit(1);\n\n\t\tUART_CLEAR_INTR(1,UART_TXFIFO_EMPTY_INT_CLR); //clear interrupt\n\t\treturn;\n\t}\n\n\n\tif( UART_INTERRUPT_IS(0,UART_RXFIFO_OVF_INT_ST) ){\t\t\n\t\t\n\t\tUART_CLEAR_INTR(0,UART_RXFIFO_OVF_INT_CLR); //clear interrupt\n\t\treturn;\n\t}\n\n    \n\n}\n\nvoid uart_register_data_callback(uart0_data_received_callback_t callback){\n\n\tuart0_data_received_callback=callback;\t\n}\nvoid uart_clear_data_callback(){\n\n\tuart0_data_received_callback=NULL;\t\n}\n\nvoid uart1_write_char(char c){\n\tuart_write_char(1,c);\n}\nvoid uart0_write_char(char c){\n\tuart_write_char(0,c);\n}\n\nvoid uart_init(UartBautRate uart0_br, UartBautRate uart1_br)\n{\n\t//set timers\n    os_memset(&tx_timer[0],0,sizeof(os_timer_t));\n    os_timer_disarm(&tx_timer[0]);\n    os_timer_setfn(&tx_timer[0], (os_timer_func_t *)tx_timer_timeout, 0);\n\n    os_memset(&tx_timer[1],0,sizeof(os_timer_t));\n    os_timer_disarm(&tx_timer[1]);\n    os_timer_setfn(&tx_timer[1], (os_timer_func_t *)tx_timer_timeout, 1);\n    \n    init_linked_list(&tx_list[0]);\n    init_linked_list(&tx_list[1]);\n\t\n\n\n\tUartDev.exist_parity = STICK_PARITY_EN;\n    UartDev.parity = EVEN_BITS;\n    UartDev.stop_bits = ONE_STOP_BIT;\n    UartDev.data_bits = EIGHT_BITS;\n\n\tUartDev.baut_rate = uart0_br;\n    uart_config(UART0);\n    UartDev.baut_rate = uart1_br;\n    uart_config(UART1);\n    ETS_UART_INTR_ENABLE();\n\n#if(DEBUG_UART==0)    \n    os_install_putc1((void *)uart0_write_char);\n#else\n    os_install_putc1((void *)uart1_write_char);\n#endif\n}"
  },
  {
    "path": "app/http/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = http.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../libc\nINCLUDES += -I ../platform\nINCLUDES += -I ../\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/http/app.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n\n\n#include \"c_types.h\"\n#include \"user_interface.h\"\n#include \"espconn.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"cgi.h\"\n#include \"cgi_wifi.h\"\n#include \"cgi_relay.h\"\n#include \"user_config.h\"\n#include \"http_server.h\"\n\n#include \"ws_app.h\"\n\n#define HTTP_PORT 80\n\n\nstatic http_server_url api_urls[]={\n\t\n//------URL-------------------------CGI----------------------ARGUMENT--------METHOD-------------FLAGS------\t\n\t{\"/api/wifi/status\",\t\thttp_wifi_api_get_status,\t\tNULL,\t\tHTTP_POST,\t\t\tNO_FLAG},\n\t{\"/api/wifi/scan\",\t\t\thttp_wifi_api_scan,\t\t\t\tNULL,\t\tHTTP_POST,\t\t\tNO_FLAG},\n\t{\"/api/wifi/connect\",\t\thttp_wifi_api_connect_ap,\t\tNULL,\t\tHTTP_POST,\t\t\tNEED_BODY},\n\t{\"/api/wifi/disconnect\",\thttp_wifi_api_disconnect,\t\tNULL,\t\tHTTP_POST,\t\t\tNO_FLAG},\n\t{\"/api/wifi/checkInternet\",\thttp_wifi_api_check_internet,\tNULL,\t\tHTTP_POST,\t\t\tNO_FLAG},\n\t{\"/api/relay/state\",\t\thttp_relay_api_status,\t\t\tNULL,\t\tHTTP_POST,\t\t\tNO_FLAG},\n\t{\"/api/relay/toggle\",\t\thttp_relay_api_toggle,\t\t\tNULL,\t\tHTTP_POST,\t\t\tNEED_BODY},\n\t{\"/api/dht/read\",\t\t\thttp_dht_api_read,\t\t\t\tNULL,\t\tHTTP_POST,\t\t\tNO_FLAG},\n\t{NULL,\t\t\t\t\t\tNULL,\t\t\t\t\t\t\tNULL,\t\tHTTP_ANY_METHOD,\tNO_FLAG}\n\t\t\n};\n\nstatic url_rewrite rewrites[]={\n//----PATH---------REWRITE-------\n\t{\"/\"\t\t\t,\t\"/index.html\"},\n\t{\"/speed-test\"\t,\t\"/speed_test.html\"},\n\t{\"/cats\"\t\t,\t\"/cats.html\"},\n\t{NULL,NULL}\n\n};\n\nvoid ICACHE_FLASH_ATTR init_http_server(){\n\n\t//general max tcp conns\n\tespconn_tcp_set_max_con(20);\n\n\thttp_server_init();\n\thttp_server_bind_domain(INTERFACE_DOMAIN);\n\thttp_server_enable_captive_portal();\n\thttp_server_enable_cors();\n\n\thttp_server_rewrite(&rewrites);\n\thttp_server_bind_urls((http_server_url *)&api_urls);\n\n\thttp_server_start();\n\n\t//ws\n\tinit_ws_server();\n\n}"
  },
  {
    "path": "app/http/app.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __HTTP_H\n#define __HTTP_H\n\nvoid ICACHE_FLASH_ATTR init_http_server();\n\n#endif\n\n"
  },
  {
    "path": "app/http/cgi.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n\n#include \"c_string.h\"\n#include \"osapi.h\" \n#include \"user_interface.h\"\n#include \"c_stdio.h\"\n#include \"mem.h\"\n\n#include \"user_config.h\"\n\n#include \"http.h\"\n#include \"http_parser.h\"\n#include \"http_server.h\"\n#include \"http_process.h\"\n#include \"http_helper.h\"\n\n#include \"rofs.h\"\n#include \"cgi.h\"\n\n\n// If a request to transmit data overflows the send buffer, the cgi function will be temporarely \n// replaced by this one and later restored when all data is sent.\nint ICACHE_FLASH_ATTR cgi_transmit(http_connection *connData){\n\n\tNODE_DBG(\"cgi_transmit\");\n\tstruct cgi_transmit_arg *arg = (struct cgi_transmit_arg*)connData->cgi.data;\n\n\tif(arg->len > 0){\n\t\tNODE_DBG(\"cgi_transmit %d bytes\",arg->len);\n\t\tint rem = connData->output.buffer + HTTP_BUFFER_SIZE - connData->output.bufferPos;\n\t\tint bytesToWrite = rem;\n\t\tif(arg->len < rem )\n\t\t\tbytesToWrite = arg->len;\n\n\t\thttp_nwrite(connData,arg->dataPos,bytesToWrite);\n\n\t\targ->len -= bytesToWrite;\n\t\targ->dataPos+=bytesToWrite;\n\n\t}\n\t\n\tif(arg->len==0){\n\n\t\t//all written\n\t\t\n\t\t//free data\n\t\tos_free(arg->data);\n\n\t\t//copy old cgi back\n\t\tos_memcpy(&connData->cgi,&arg->previous_cgi,sizeof(cgi_struct));\n\n\t\t//free cgi arg\n\t\tos_free(arg);\n\n\t}\n\n\treturn HTTPD_CGI_MORE;\n\n}\n\n\n// This makes sure we aren't serving static files on POST requests for example\nint ICACHE_FLASH_ATTR cgi_enforce_method(http_connection *connData) {\t\n\n\tenum http_method *method = (enum http_method *)connData->cgi.argument;\n\n\tif(connData->state == HTTPD_STATE_BODY_END)\n\tif(connData->parser.method!=*method && (int)*method>=0)\n\t{\n\t\tNODE_DBG(\"Wrong HTTP method. Enforce is %d and request is %d\",method,connData->parser.method);\n\n\t\thttp_response_BAD_REQUEST(connData);\n\t\treturn HTTPD_CGI_DONE;\n\t}\n\t\n\n\treturn HTTPD_CGI_NEXT_RULE;\n}\n\n// This makes sure we have a body\nint ICACHE_FLASH_ATTR cgi_enforce_body(http_connection *connData) {\t\n\n\tif(connData->state ==HTTPD_STATE_ON_URL){\t\n\t\thttp_set_save_body(connData); //request body to be saved\n\t}\n\n\t//wait for whole body\n\tif(connData->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_NEXT_RULE; \n\n\t//if body empty, bad request\n\tif(connData->body.len <=0){\n\t\thttp_response_BAD_REQUEST(connData);\n\t\tNODE_DBG(\"No body\");\t\t\n\t\treturn HTTPD_CGI_DONE;\n\t}\n\telse\n\t\treturn HTTPD_CGI_NEXT_RULE;\n\n\t\n}\n\n//cgi that adds CORS ( Cross Origin Resource Sharing ) to our server\nint ICACHE_FLASH_ATTR cgi_cors(http_connection *connData) {\n\t\n\thttp_server_config *config = (http_server_config*)connData->cgi.argument;;\n\tif(config==NULL)\n\t\treturn HTTPD_CGI_NEXT_RULE;\n\n\tif(!config->enable_cors)\n\t\treturn HTTPD_CGI_NEXT_RULE;\n\n\n\tif(connData->state==HTTPD_STATE_ON_URL){\n\n\t\t//save cors headers \n\t\thttp_set_save_header(connData,HTTP_ACCESS_CONTROL_REQUEST_HEADERS);\n\t\thttp_set_save_header(connData,HTTP_ACCESS_CONTROL_REQUEST_METHOD);\n\t\t\n\t\treturn HTTPD_CGI_NEXT_RULE;\n\t}\n\t\n\tif(connData->state==HTTPD_STATE_HEADERS_END){\n\n\t\t//SET CORS Allow Origin for every request\n\t\thttp_SET_HEADER(connData,HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,\"*\");\n\n\t\theader * allow_headers = http_get_header(connData,HTTP_ACCESS_CONTROL_REQUEST_HEADERS);\n\t\theader * allow_methods = http_get_header(connData,HTTP_ACCESS_CONTROL_REQUEST_METHOD);\n\t\t\n\t\tif(allow_headers!=NULL)\n\t\t\thttp_SET_HEADER(connData,HTTP_ACCESS_CONTROL_ALLOW_HEADERS,allow_headers->value);\n\t\tif(allow_methods!=NULL)\n\t\t\thttp_SET_HEADER(connData,HTTP_ACCESS_CONTROL_ALLOW_METHODS,allow_methods->value);\n\n\t\t// Browsers will send an OPTIONS pre-flight request when posting data on a cross-domain situation\n\t\t// If that's the case here, we can safely return 200 OK with our CORS headers set\n\t\tif(connData->parser.method==HTTP_OPTIONS)\n\t\t{\n\t\t\thttp_response_OK(connData);\n\t\t\treturn HTTPD_CGI_DONE;\n\t\t}\n\t}\n\n\treturn HTTPD_CGI_NEXT_RULE;\n}\n\n//Simple static url rewriter, allows us to process the request as another url without redirecting the user\n//Used to serve index files on root / requests for example\nint ICACHE_FLASH_ATTR cgi_url_rewrite(http_connection *connData) {\t\n\n\tif(connData->state==HTTPD_STATE_HEADERS_END){\n\n\t\tNODE_DBG(\"Rewrite %s to %s\",connData->url,(char*)connData->cgi.argument);\n\t\n\t\tint urlSize = strlen((char*)connData->cgi.argument);\n\t\tif(urlSize < URL_MAX_SIZE){\n\t\t\tstrcpy(connData->url,(char*)connData->cgi.argument);\t\n\t\t\t//re-parse url\n\t\t\thttp_parse_url(connData);\n\t\t}\n\t\t\n\t}\n\n\treturn HTTPD_CGI_NEXT_RULE;\n}\n\n//Simple cgi that redirects the user\nint ICACHE_FLASH_ATTR cgi_redirect(http_connection *connData) {\n\t\n\thttp_response_REDIRECT(connData, (char*)connData->cgi.argument);\n\treturn HTTPD_CGI_DONE;\n}\n\n//Cgi that check the request has the correct HOST header\n//Using it we can ensure our server has a domain of our choice\nint ICACHE_FLASH_ATTR cgi_check_host(http_connection *connData) {\n\t\n\thttp_server_config *config = (http_server_config*)connData->cgi.argument;\n\tif(config==NULL)\n\t\treturn HTTPD_CGI_NEXT_RULE;\n\n\tif(config->host_domain==NULL)\n\t\treturn HTTPD_CGI_NEXT_RULE;\n\n\t\n\tif(connData->state==HTTPD_STATE_ON_URL){\n\n\t\thttp_set_save_header(connData,HTTP_HOST);\n\t\treturn HTTPD_CGI_NEXT_RULE;\n\t}\n\n\tif(connData->state==HTTPD_STATE_HEADERS_END){\n\n\t\theader *hostHeader = http_get_header(connData,HTTP_HOST);\n\t\tif(hostHeader==NULL){\n\t\t\tNODE_DBG(\"Host header not found\");\n\t\t\thttp_response_BAD_REQUEST(connData);\n\t\t\treturn HTTPD_CGI_DONE;\n\t\t}\n\n\t\tconst char * domain = config->host_domain;\n\n\t\tNODE_DBG(\"Host header found: %s, domain: %s\",hostHeader->value,domain);\n\n\n\t\tif(os_strncmp(hostHeader->value,domain,strlen(domain))==0) //compare ignoring http:// and last /\n\t\t{\n\t\t\tNODE_DBG(\"Hosts match\");\n\t\t\treturn HTTPD_CGI_NEXT_RULE;\n\t\t}\n\t\telse{\n\t\t\tNODE_DBG(\"Hosts don't match\");\n\t\t\t\n\t\t\tif(config->enable_captive){\n\t\t\t\t//to enable a captive portal we should redirect here\n\n\t\t\t\tchar * redirectUrl = (char *)os_zalloc(strlen(domain)+9); // domain lenght + http:// + / + \\0\n\t\t\t\tos_strcpy(redirectUrl,\"http://\");\n\t\t\t\tos_strcat(redirectUrl,domain);\n\t\t\t\tos_strcat(redirectUrl,\"/\");\n\n\t\t\t\thttp_response_REDIRECT(connData, redirectUrl);\n\n\t\t\t\tos_free(redirectUrl);\n\n\t\t\t}\n\t\t\telse{\n\t\t\t\t//bad request\n\t\t\t\thttp_response_BAD_REQUEST(connData);\n\n\t\t\t}\n\t\t\t\n\t\t\t\n\n\t\t\treturn HTTPD_CGI_DONE;\n\t\t}\n\t\t\n\n\t}\n\n\t\n\treturn HTTPD_CGI_NEXT_RULE;\n\n}\n\ntypedef struct{\n\tRO_FILE *f;\n\tchar *buff;\n} cgi_fs_state;\n\n//cgi for static file serving\nint ICACHE_FLASH_ATTR cgi_file_system(http_connection *connData) {\n\n\tcgi_fs_state *state = (cgi_fs_state *)connData->cgi.data;\n\n\tint len;\n\tchar buff[HTTP_BUFFER_SIZE];\t\t\n\t\n\t//wait for body end state\n\tif(connData->state<HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_NEXT_RULE; \t\n\n\tif (state==NULL) {\n\t\t//First call to this cgi. Open the file so we can read it.\n\t\t\n\t\tRO_FILE *f;\n\t\tif( ! connData->url_parsed.field_set & (1<<UF_PATH) ){\n\t\t\t//there's no PATH on the url ( WTF? ), so not found\n\t\t\treturn HTTPD_CGI_NOTFOUND;\n\t\t}\n\n\t\tchar * path = http_url_get_path(connData);\n\t\t\n\t\tf=f_open(path);\t\t\n\n\t\tif (f==NULL) {\n\t\t\treturn HTTPD_CGI_NOTFOUND;\n\t\t}\n\n\t\tNODE_DBG(\"File %s opened\",path);\n\n\t\tstate = (cgi_fs_state*)os_zalloc(sizeof(cgi_fs_state));\n\t\tstate->f = f;\n\t\tconnData->cgi.data=state; //save state for next time\n\t\t\n\t\t//set headers\n\t\thttp_SET_HEADER(connData,HTTP_CONTENT_TYPE,http_get_mime(connData->url));\t\n\t\thttp_SET_HEADER(connData,HTTP_CACHE_CONTROL,HTTP_DEFAULT_CACHE);\n\t\thttp_SET_CONTENT_LENGTH(connData,f->file->size);\n\n\t\tif(f->file->gzip)\n\t\t\thttp_SET_HEADER(connData,HTTP_CONTENT_ENCODING,\"gzip\");\n\n\t\thttp_response_OK(connData);\t\t\n\t\t\n\t\t\n\t\treturn HTTPD_CGI_MORE;\n\t}\n\telse{\n\t\t//file found, transmit data\n\n\t\tlen=f_read(state->f, buff, HTTP_BUFFER_SIZE);\n\t\tif (len>0){\n\t\t\tNODE_DBG(\"Sending %d bytes of data\",len);\n\t\t\thttp_nwrite(connData,(const char*)buff,len);\n\t\t\t//http_response_transmit(connData);\n\t\t} \n\t\tif (state->f->eof) {\n\t\t\tNODE_DBG(\"End of file reached\");\n\t\t\t//We're done.\n\t\t\tf_close(state->f);\n\t\t\tos_free(state);\n\t\t\treturn HTTPD_CGI_DONE;\n\t\t} else {\n\t\t\t//not done yet\n\t\t\treturn HTTPD_CGI_MORE;\n\t\t}\n\n\t}\n\n\t\n}\n"
  },
  {
    "path": "app/http/cgi.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef CGI_H\n#define CGI_H\n\n#include \"http.h\"\n\n\nstruct cgi_transmit_arg{\n\tcgi_struct previous_cgi;\n\n\tuint8_t *data;\n\tuint8_t *dataPos;\n\tuint16_t len;\n\n};\n\nint ICACHE_FLASH_ATTR cgi_transmit(http_connection *connData);\nint ICACHE_FLASH_ATTR cgi_cors(http_connection *connData);\nint ICACHE_FLASH_ATTR cgi_url_rewrite(http_connection *connData);\nint ICACHE_FLASH_ATTR cgi_redirect(http_connection *connData);\nint ICACHE_FLASH_ATTR cgi_check_host(http_connection *connData);\nint ICACHE_FLASH_ATTR cgi_file_system(http_connection *connData);\nint ICACHE_FLASH_ATTR cgi_enforce_method(http_connection *connData);\n\n\n#endif"
  },
  {
    "path": "app/http/cgi_relay.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"c_string.h\"\n#include \"osapi.h\"\n#include \"user_interface.h\"\n#include \"mem.h\"\n#include \"c_stdio.h\"\n#include \"platform.h\"\n#include \"user_config.h\"\n#include \"driver/relay.h\"\n#include \"sensor/sensors.h\"\n\n#include \"cgi.h\"\n\n#include \"http.h\"\n#include \"http_parser.h\"\n#include \"http_server.h\"\n#include \"http_process.h\"\n#include \"http_helper.h\"\n#include \"http_client.h\"\n\n#include \"json/cJson.h\"\n\n\n\nint ICACHE_FLASH_ATTR http_relay_api_status(http_connection *c) {\n\n\n\tNODE_DBG(\"http_wifi_api_get_status\");\n\t\t\n\t//wait for whole body\n\tif(c->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_MORE; \t\n\n\t//write headers\n\thttp_SET_HEADER(c,HTTP_CONTENT_TYPE,JSON_CONTENT_TYPE);\t\n\thttp_response_OK(c);\n\n\tcJSON *root, *relays, *fld;\n\n\troot = cJSON_CreateObject(); \n\tcJSON_AddItemToObject(root, \"relays\", relays = cJSON_CreateArray());\n\t\n\tint i;\n\tfor(i=0;i<relay_count();i++){\n\n\t\tcJSON_AddItemToArray(relays,fld=cJSON_CreateObject());\n\t\tcJSON_AddNumberToObject(fld,\"relay\",i);\n\t\tcJSON_AddNumberToObject(fld,\"state\",relay_get_state(i));\n\t\t\n\t}\n\n\thttp_write_json(c,root);\t\n\n\t//delete json struct\n\tcJSON_Delete(root);\n\n\treturn HTTPD_CGI_DONE;\n\n\n}\n\nint ICACHE_FLASH_ATTR http_relay_api_toggle(http_connection *c) {\n\n\n\tNODE_DBG(\"http_wifi_api_get_status\");\t\n\t\n\n\t//wait for whole body\n\tif(c->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_MORE; \n\n\t//parse json\n\tcJSON * root = cJSON_Parse(c->body.data);\n\tif(root==NULL) goto badrequest;\n\t\n\tcJSON * relay = cJSON_GetObjectItem(root,\"relay\");\n\tif(relay==NULL) goto badrequest;\n\n\n\tint relayNumber = relay->valueint;\n\tcJSON_Delete(root);\t\n\n\tif(relayNumber<0 || relayNumber >=relay_count()){\n\t\thttp_response_BAD_REQUEST(c);\n\t\tNODE_DBG(\"Wrong relay\");\t\t\n\t\treturn HTTPD_CGI_DONE;\n\t}\n\telse{\n\t\t//valid relay\n\n\t\tunsigned status = relay_get_state(relayNumber);\n\t\tstatus = relay_toggle_state(relayNumber);\n\n\t\t//write headers\n\t\thttp_SET_HEADER(c,HTTP_CONTENT_TYPE,JSON_CONTENT_TYPE);\t\n\t\thttp_response_OK(c);\n\n\n\t\t//create json\n\t\troot = cJSON_CreateObject();\n\t\tcJSON_AddNumberToObject(root,\"relay\",relayNumber);\n\t\tcJSON_AddNumberToObject(root,\"state\",status);\n\n\t\thttp_write_json(c,root);\n\n\t\t//delete json struct\n\t\tcJSON_Delete(root);\n\n\t\treturn HTTPD_CGI_DONE;\n\n\t}\t\n\nbadrequest:\n\thttp_response_BAD_REQUEST(c);\n\treturn HTTPD_CGI_DONE;\n\n}\n\n//TODO move to own file\nint ICACHE_FLASH_ATTR http_dht_api_read(http_connection *c) {\n\n\n\tNODE_DBG(\"http_dht_api_read\");\n\t\t\n\t//wait for whole body\n\tif(c->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_MORE; \t\n\n\t//write headers\n\thttp_SET_HEADER(c,HTTP_CONTENT_TYPE,JSON_CONTENT_TYPE);\t\n\thttp_response_OK(c);\n\n\tsensor_data data;\n\tsensors_get_data(&data);\n\t\t\n\t//create json\n\tcJSON *root = cJSON_CreateObject();\n\tcJSON_AddNumberToObject(root,\"temp\",data.dht22.temp);\n\tcJSON_AddNumberToObject(root,\"hum\",data.dht22.hum);\n\n\t//write json\n\thttp_write_json(c,root);\n\n\t//delete json struct\n\tcJSON_Delete(root);\n\t\t\t\t\n\treturn HTTPD_CGI_DONE;\n\n\n}\n\n"
  },
  {
    "path": "app/http/cgi_relay.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef CGI_RELAY_H\n#define CGI_RELAY_H\n\nint ICACHE_FLASH_ATTR http_relay_api_status(http_connection *c);\nint ICACHE_FLASH_ATTR http_relay_api_toggle(http_connection *c);\nint ICACHE_FLASH_ATTR http_dht_api_read(http_connection *c);\n#endif"
  },
  {
    "path": "app/http/cgi_wifi.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"c_string.h\"\n#include \"osapi.h\"\n#include \"user_interface.h\"\n#include \"mem.h\"\n#include \"espconn.h\"\n#include \"c_stdio.h\"\n#include \"user_config.h\"\n #include <limits.h>\n\n#include \"cgi.h\"\n\n#include \"http.h\"\n#include \"http_parser.h\"\n#include \"http_server.h\"\n#include \"http_process.h\"\n#include \"http_helper.h\"\n#include \"http_client.h\"\n\n#include \"json/cJson.h\"\n\n//WiFi access point data\ntypedef struct {\n\tchar ssid[32];\n\tchar rssi;\n\tchar enc;\n\tchar channel;\n} ap;\n\n//Scan result\ntypedef struct {\t\n\tap **ap;\n\tint ap_count;\n} scan_result_data;\n\ntypedef struct { \n\tuint8_t scanning;\n\tuint8_t connecting;\n\tscan_result_data scan_result;\n\tuint8_t mode;\n\tuint8_t station_status;\n\tstruct station_config station_config;\n\n} wifi_status_t;\n\n\ntypedef struct {\n\n\tuint8_t state;\n\tETSTimer timer;\n\n} api_cgi_status;\n\n\n\ntypedef struct {\n\n\tuint8_t state;\n\tETSTimer timer;\n\tchar ssid[32];\n\tchar pwd[64];\n\n} api_cgi_connect_status;\n\ntypedef struct {\n\tuint8_t state;\n\thttp_connection *http_client;\t\n} api_cgi_check_internet_status;\n\nstatic wifi_status_t wifi_status;\n\nstruct station_config *wifi_st_config;\n\nint ICACHE_FLASH_ATTR http_wifi_api_get_status(http_connection *c) {\n\n\tNODE_DBG(\"http_wifi_api_get_status\");\n\t\n\t\n\t//wait for whole body\n\tif(c->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_MORE; \n\t\n\n\tapi_cgi_status * status = c->cgi.data;\n\n\tif(status==NULL){ //first call, send headers\n\n\t\tNODE_DBG(\"\\tSending headers\");\n\n\t\tstatus = (api_cgi_status*)os_malloc(sizeof(api_cgi_status));\n\t\tstatus->state=1;\n\t\tc->cgi.data=status;\n\n\t\thttp_SET_HEADER(c,HTTP_CONTENT_TYPE,JSON_CONTENT_TYPE);\n\t\thttp_response_OK(c);\t\t\t\n\n\t\tNODE_DBG(\"\\tHeaders done\");\n\t\t\n\t\treturn HTTPD_CGI_MORE;\n\t}\n\telse if(status->state==1){\n\t\t//json data\n\n\t\tNODE_DBG(\"\\tSending json\");\n\n\t\twifi_station_get_config(&wifi_status.station_config);\n\n\t\tuint8_t c_status = wifi_station_get_connect_status();\n\n\t\tcJSON *root = cJSON_CreateObject();\n\t\tcJSON_AddBoolToObject(root,\"scanning\",wifi_status.scanning);\n\t\tcJSON_AddStringToObject(root,\"ssid\",(const char *)wifi_status.station_config.ssid);\n\t\tcJSON_AddNumberToObject(root,\"mode\",wifi_get_opmode());\n\t\tcJSON_AddNumberToObject(root,\"station_status\",c_status);\t\t\n\n\t\tif(c_status==5){ //got ip\n\t\t\tstruct ip_info ip;\n\t\t\twifi_get_ip_info(0x0,&ip);\n\t\t\tchar *ip_str = ipaddr_ntoa(&ip.ip);\n\t\t\tcJSON_AddStringToObject(root,\"ip\",ip_str);\n\t\t}\n\t\telse{\n\t\t\tcJSON_AddStringToObject(root,\"ip\",\"\");\n\t\t}\n\n\t\thttp_write_json(c,root);\n\t\tcJSON_Delete(root);\n\t\t\n\t\tstatus->state=99;\n\t\treturn HTTPD_CGI_MORE;\t\t\n\t}\t\n\telse{\n\t\tos_free(c->cgi.data);\n\t\treturn HTTPD_CGI_DONE;\t\n\t}\n\n\n}\n\n\nstatic void ICACHE_FLASH_ATTR http_wifi_api_scan_callback(void *arg, STATUS status){\n\n\tint n;\n\tstruct bss_info *bss_link = (struct bss_info *)arg;\n\tNODE_DBG(\"Wifi Scan Done, status: %d\", status);\n\tif (status!=OK) {\n\t\twifi_status.scanning=0;\n\t\treturn;\n\t}\n\n\t//Clear prev ap data if needed.\n\tif (wifi_status.scan_result.ap!=NULL) {\n\t\tfor (n=0; n<wifi_status.scan_result.ap_count; n++) \n\t\t\tos_free(wifi_status.scan_result.ap[n]);\n\t\tos_free(wifi_status.scan_result.ap);\n\t}\n\n\t//Count amount of access points found.\n\tn=0;\n\twhile (bss_link != NULL) {\n\t\tbss_link = bss_link->next.stqe_next;\n\t\tn++;\n\t}\n\n\t//Allocate memory for access point data\n\twifi_status.scan_result.ap=(ap **)os_malloc(sizeof(ap *)*n);\n\twifi_status.scan_result.ap_count=n;\n\tNODE_DBG(\"Scan done: found %d APs\", n);\n\n\t//Copy access point data to the static struct\n\tn=0;\n\tbss_link = (struct bss_info *)arg;\n\twhile (bss_link != NULL) {\n\t\tif (n>=wifi_status.scan_result.ap_count) {\n\t\t\t//This means the bss_link changed under our nose. Shouldn't happen!\n\t\t\t//Break because otherwise we will write in unallocated memory.\n\t\t\tNODE_DBG(\"Huh? I have more than the allocated %d aps!\", wifi_status.scan_result.ap_count);\n\t\t\tbreak;\n\t\t}\n\t\t//Save the ap data.\n\t\tif(strlen(bss_link->ssid)>0){\n\t\t\twifi_status.scan_result.ap[n]=(ap *)os_malloc(sizeof(ap));\n\t\t\twifi_status.scan_result.ap[n]->rssi=bss_link->rssi;\n\t\t\twifi_status.scan_result.ap[n]->enc=bss_link->authmode;\n\t\t\twifi_status.scan_result.ap[n]->channel=bss_link->channel;\n\t\t\tstrncpy(wifi_status.scan_result.ap[n]->ssid, (char*)bss_link->ssid, 32);\t\t\t\n\t\t\tn++;\n\t\t}\n\t\telse{\n\t\t\twifi_status.scan_result.ap_count--;\n\t\t}\n\n\t\tbss_link = bss_link->next.stqe_next;\n\t\t\n\t}\n\n\t//We're done.\n\twifi_status.scanning=0;\n\n}\n\ntypedef struct {\n\n\tuint8_t state;\n\tETSTimer timer;\n\tint ap_index;\n\n} api_cgi_scan_status;\n\nint ICACHE_FLASH_ATTR http_wifi_api_scan(http_connection *c) {\n\t\t\n\tNODE_DBG(\"http_wifi_api_scan\");\n\n\t\n\t//wait for whole body\n\tif(c->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_MORE; \n\n\n\tapi_cgi_scan_status * status = c->cgi.data;\n\tif(status==NULL){ //first call, create status\n\n\t\t//create status\n\t\tstatus = (api_cgi_scan_status*)os_malloc(sizeof(api_cgi_scan_status));\n\t\tstatus->state=1;\n\t\tstatus->ap_index=0;\n\t\tc->cgi.data=status;\n\n\t\tif(!wifi_status.scanning){\n\t\t\t//if not already scanning, request scan\n\n\t\t\tNODE_DBG(\"Starting scan\");\n\n\t\t\twifi_station_scan(NULL,http_wifi_api_scan_callback);\n\n\t\t\twifi_status.scanning=1;\n\n\t\t}\n\n\t\t//write headers\n\t\thttp_SET_HEADER(c,HTTP_CONTENT_TYPE,JSON_CONTENT_TYPE);\t\n\t\thttp_response_OK(c);\t\t\t\n\n\t\t//set state to 1 - waiting\n\t\tstatus->state=1;\n\t\t\n\t\treturn HTTPD_CGI_MORE;\n\n\t}\n\telse{\t\t\n\n\t\tif(wifi_status.scanning){\n\t\t\tNODE_DBG(\"Waiting scan done\");\n\n\t\t\t//set timer to check again\n\t\t\tos_timer_disarm(&status->timer);\n\t\t\tos_timer_setfn(&status->timer, http_execute_cgi, c);\n\t\t\tos_timer_arm(&status->timer, 500, 0);\n\n\t\t\treturn HTTPD_CGI_MORE;\n\t\t}\t\t\t\n\t\telse if(status->state==1){\t\n\t\t\t\n\t\t\t//clear timer\n\t\t\tos_timer_disarm(&status->timer);\n\n\t\t\tNODE_DBG(\"Scan complete %d\",status->ap_index);\n\n\t\t\t//create json\n\t\t\tcJSON *root = cJSON_CreateObject();\n\t\t\tcJSON_AddNumberToObject(root,\"ap_count\",wifi_status.scan_result.ap_count);\n\n\t\t\tcJSON * array;\n\t\t\tcJSON * item;\n\t\t\tcJSON_AddItemToObject(root, \"ap\", array = cJSON_CreateArray());\n\n\n\t\t\t//check max count on query string\n\t\t\tchar *query=http_url_get_query_param(c,\"max\");\n\t\t\tint max = INT_MAX;\n\t\t\tif(query!=NULL)\t\t\n\t\t\t\tmax = atoi(query);\n\n\t\t\tint i;\n\t\t\tfor(i=0;i< wifi_status.scan_result.ap_count && i<max;i++){\n\n\t\t\t\tcJSON_AddItemToArray(array,item=cJSON_CreateObject());\n\t\t\t\tcJSON_AddStringToObject(item,\"ssid\",(const char *)wifi_status.scan_result.ap[i]->ssid);\n\t\t\t\tcJSON_AddNumberToObject(item,\"rssi\",wifi_status.scan_result.ap[i]->rssi);\n\t\t\t\tcJSON_AddNumberToObject(item,\"enc\",wifi_status.scan_result.ap[i]->enc);\n\t\t\t\tcJSON_AddNumberToObject(item,\"channel\",wifi_status.scan_result.ap[i]->channel);\n\n\t\t\t}\n\n\t\t\thttp_write_json(c,root);\t\n\n\t\t\t//delete json struct\n\t\t\tcJSON_Delete(root);\n\n\t\t\tstatus->state=99; \t\t\n\t\t\treturn HTTPD_CGI_MORE;\n\t\t\t\t\t\t\n\t\t\t\n\t\t}\n\t\telse{ //free resources\n\n\t\t\tNODE_DBG(\"Freeing alloced memory\");\n\t\t\tos_free(c->cgi.data); \t\t\n\n\t\t\treturn HTTPD_CGI_DONE;\n\t\t}\n\n\t}\n\n}\n\nint ICACHE_FLASH_ATTR http_wifi_api_disconnect(http_connection *c){\n\n\tNODE_DBG(\"http_wifi_disconnect\");\n\n\t\n\t//wait for whole body\n\tif(c->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_MORE; \n\t\n\n\t//reset wifi cfg\n\tstrcpy(wifi_status.station_config.ssid,\"\");\n\tstrcpy(wifi_status.station_config.password,\"\");\n\twifi_status.station_config.bssid_set=0;\n\n\twifi_station_disconnect();\n\twifi_station_set_config(&wifi_status.station_config);\n\n\thttp_response_OK(c);\n\treturn HTTPD_CGI_DONE;\n}\n\nint ICACHE_FLASH_ATTR http_wifi_api_connect_ap(http_connection *c){\n\n\tNODE_DBG(\"http_wifi_api_connect_ap\");\n\n\t\t\n\t//wait for whole body\n\tif(c->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_MORE; \t\n\t\n\t\n\tapi_cgi_connect_status * status = c->cgi.data;\n\n\tif(status==NULL){\n\t\tNODE_DBG(\"http_wifi_api_connect_ap status NULL\");\n\n\t\tstatus = (api_cgi_connect_status*)os_malloc(sizeof(api_cgi_connect_status));\n\t\tstatus->state=1;\n\t\tc->cgi.data=status;\n\t\t\n\n\t\t//parse json and validate\n\t\tcJSON * root = cJSON_Parse(c->body.data);\n\t\tif(root==NULL) goto badrequest;\n\t\t\n\t\tcJSON * ssid = cJSON_GetObjectItem(root,\"ssid\");\n\t\tif(ssid==NULL) goto badrequest;\n\t\telse if(ssid->type != cJSON_String) goto badrequest;\n\n\t\tcJSON * pwd = cJSON_GetObjectItem(root,\"pwd\");\n\t\tif(pwd==NULL) goto badrequest;\n\t\telse if(pwd->type!=cJSON_String) goto badrequest;\n\t\t\n\t\t//parse ok\n\t\tstrncpy(status->ssid,ssid->valuestring,32);\n\t\tstrncpy(status->pwd,pwd->valuestring,64);\n\n\t\t//set timer to connect \n\t\tos_timer_disarm(&status->timer);\n\t\tos_timer_setfn(&status->timer, http_execute_cgi, c);\n\t\tos_timer_arm(&status->timer, 10, 0);\n\n\t\treturn HTTPD_CGI_MORE;\n\n\t\n\n\t}\n\telse if(status->state==1){\n\t\t\tNODE_DBG(\"http_wifi_api_connect_ap status %d\",status->state);\n\t\t\t//try connect\n\n\t\t\tif(strlen(status->ssid)>32 || strlen(status->pwd)>64)\n\t\t\t\tgoto badrequest;\n\n\t\t\tNODE_DBG(\"http_wifi_api_connect_ap ssid %s\",status->ssid);\n\t\t\tNODE_DBG(\"http_wifi_api_connect_ap pwd %s\",status->pwd);\n\n\t\t\tstrcpy(wifi_status.station_config.ssid,status->ssid);\n\t\t\tstrcpy(wifi_status.station_config.password,status->pwd);\n\t\t\twifi_status.station_config.bssid_set=0;\n\n\t\t\twifi_station_disconnect();\n\t\t\twifi_station_set_config(&wifi_status.station_config);\n\t\t\twifi_station_connect();\n\n\t\t\t//set timer to check status\n\t\t\tos_timer_disarm(&status->timer);\n\t\t\tos_timer_setfn(&status->timer, http_execute_cgi, c);\n\t\t\tos_timer_arm(&status->timer, 500, 0);\n\n\t\t\tstatus->state=2;\n\n\t\t\treturn HTTPD_CGI_MORE;\n\n\t\t\t\n\t}\n\telse if(status->state==2){\n\t\tNODE_DBG(\"http_wifi_api_connect_ap status %d\",status->state);\n\n\t\tuint8_t c_status = wifi_station_get_connect_status();\n\n\t\tNODE_DBG(\"http_wifi_api_connect_ap wifi status %d\",c_status);\n\n\t\tif(c_status>=2 && c_status <= 4 ){\n\n\t\t\twifi_station_disconnect();\n\t\t\tstrcpy(wifi_status.station_config.ssid,\"\");\n\t\t\tstrcpy(wifi_status.station_config.password,\"\");\n\t\t\twifi_station_set_config(&wifi_status.station_config);\n\n\t\t}\n\n\t\tif(c_status==1){\n\t\t\t//set timer to check status\n\t\t\tos_timer_disarm(&status->timer);\n\t\t\tos_timer_setfn(&status->timer, http_execute_cgi, c);\n\t\t\tos_timer_arm(&status->timer, 500, 0);\n\t\t\treturn HTTPD_CGI_MORE;\n\t\t}\n\t\telse{\n\n\t\t\t//write headers\n\t\t\thttp_SET_HEADER(c,HTTP_CONTENT_TYPE,JSON_CONTENT_TYPE);\n\t\t\thttp_response_OK(c);\n\n\t\t\t//create json\n\t\t\tcJSON *root = cJSON_CreateObject();\n\t\t\tcJSON_AddNumberToObject(root,\"status\",c_status);\t\t\t\n\t\t\t\n\t\t\tif(c_status==5){ //got ip\n\t\t\t\tstruct ip_info ip;\n\t\t\t\twifi_get_ip_info(0x0,&ip);\n\t\t\t\tchar *ip_str = ipaddr_ntoa(&ip.ip);\n\t\t\t\tcJSON_AddStringToObject(root,\"ip\",ip_str);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tcJSON_AddStringToObject(root,\"ip\",\"\");\n\t\t\t}\n\n\t\t\thttp_write_json(c,root);\n\n\t\t\t//delete json struct\n\t\t\tcJSON_Delete(root);\t\n\n\t\t\tstatus->state=99;\n\t\t\t\n\t\t\treturn HTTPD_CGI_MORE;\t\t\n\t\t}\t\t\n\n\t}\t\n\telse{ //=99\n\t\tNODE_DBG(\"http_wifi_api_connect_ap status %d\",status->state);\t\t\n\t\t//clean\n\t\tos_free(c->cgi.data);\n\t\treturn HTTPD_CGI_DONE;\n\t}\n\nbadrequest:\n\thttp_response_BAD_REQUEST(c);\n\tstatus->state=99;\t\n\treturn HTTPD_CGI_MORE;\n\t\n\t//shut up compiler\n\treturn HTTPD_CGI_DONE;\n}\n\nint ICACHE_FLASH_ATTR http_wifi_api_check_internet_cb(http_connection *c){\n\n\n\tNODE_DBG(\"http_wifi_api_check_internet_cb state: %d\",c->state);\n\n\thttp_connection *request=c->reverse;\n\n\tif(request->espConnection==NULL)\n\t{\n\t\t//client request has been aborted\n\t\treturn HTTP_CLIENT_CGI_DONE;\n\t}\n\n\tapi_cgi_check_internet_status * status = (api_cgi_check_internet_status *)request->cgi.data;\n\n\n\tif(c->state==HTTP_CLIENT_DNS_NOT_FOUND){\n\t\tstatus->state=3;\n\t\thttp_execute_cgi(request);\n\t\treturn HTTP_CLIENT_CGI_DONE;\n\t}\n\n\t//wait whole body \n\tif(c->state==HTTPD_STATE_BODY_END){\n\n\t\tif(c->parser.status_code==200)\n\t\t\tstatus->state=2;\t\t\n\t\telse\n\t\t\tstatus->state=3;\n\n\t\thttp_execute_cgi(request);\n\t\t\n\t\treturn HTTP_CLIENT_CGI_DONE;\n\t}\n\n\treturn HTTP_CLIENT_CGI_MORE;\t\n}\n\nint ICACHE_FLASH_ATTR http_wifi_api_check_internet(http_connection *c){\n\n\tNODE_DBG(\"http_wifi_api_check_internet\");\n\n\t//wait for whole body\n\tif(c->state <HTTPD_STATE_BODY_END)\n\t\treturn HTTPD_CGI_MORE; \t\t\n\n\tapi_cgi_check_internet_status * status = (api_cgi_check_internet_status *)c->cgi.data;\n\tif(status==NULL){ //first call, send headers\n\n\t\tNODE_DBG(\"http_wifi_api_check_internet null\");\n\n\t\tstatus = (api_cgi_check_internet_status*)os_malloc(sizeof(api_cgi_check_internet_status));\n\t\tstatus->state=1;\n\t\tc->cgi.data=status;\n\n\t\thttp_SET_HEADER(c,HTTP_CONTENT_TYPE,JSON_CONTENT_TYPE);\n\t\thttp_response_OK(c);\t\t\t\n\n\t\tstatus->http_client = http_client_new(http_wifi_api_check_internet_cb);\n\t\thttp_client_GET(status->http_client,\"http://www.msftncsi.com/ncsi.txt\");\n\t\t\n\t\tstatus->http_client->reverse = c; //mark reverse so we can find on callback\n\t\tc->reverse=&status->http_client; //reverse other way around\n\n\t\treturn HTTPD_CGI_MORE;\n\t}\n\telse if(status->state==1){\n\t\t// just signal we aren't finished\n\t\tNODE_DBG(\"http_wifi_api_check_internet 1\");\t\t\n\t\treturn HTTPD_CGI_MORE;\n\t}\n\telse if(status->state==2){\n\t\t//DNS FOUND\n\t\tNODE_DBG(\"http_wifi_api_check_internet 2\");\n\n\t\tstatus->state=99;\t\n\t\t\n\t\t//create json\n\t\tcJSON *root = cJSON_CreateObject();\n\t\tcJSON_AddNumberToObject(root,\"status\",1);\t\t\n\n\t\thttp_write_json(c,root);\n\t\t//delete json struct\n\t\tcJSON_Delete(root);\t\n\t\n\n\t\treturn HTTPD_CGI_MORE;\n\n\t}\n\telse if(status->state==3){\n\t\t//DNS NOT FOUND\n\t\tstatus->state=99;\t\n\t\t\t\n\t\t//create json\n\t\tcJSON *root = cJSON_CreateObject();\n\t\tcJSON_AddNumberToObject(root,\"status\",0);\t\t\n\n\t\thttp_write_json(c,root);\n\t\t//delete json struct\n\t\tcJSON_Delete(root);\t\n\n\t\treturn HTTPD_CGI_MORE;\n\t}\n\telse{\n\t\tNODE_DBG(\"http_wifi_api_check_internet 99\");\n\t\tos_free(c->cgi.data);\n\t\treturn HTTPD_CGI_DONE;\n\n\t}\n}\n\n\n\n"
  },
  {
    "path": "app/http/cgi_wifi.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef CGI_WIFI_H\n#define CGI_WIFI_H\n\nint ICACHE_FLASH_ATTR http_wifi_api_get_status(http_connection *c);\nint ICACHE_FLASH_ATTR http_wifi_api_scan(http_connection *c);\nint ICACHE_FLASH_ATTR http_wifi_api_connect_ap(http_connection *c);\nint ICACHE_FLASH_ATTR http_wifi_api_disconnect(http_connection *c);\nint ICACHE_FLASH_ATTR http_wifi_api_check_internet(http_connection *c);\n#endif"
  },
  {
    "path": "app/http/html/.bak/bootstrap.css",
    "content": "/*!\r\n * bootswatch v3.3.4+1\r\n * Homepage: http://bootswatch.com\r\n * Copyright 2012-2015 Thomas Park\r\n * Licensed under MIT\r\n * Based on Bootstrap\r\n*/\r\n/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\r\nhtml {\r\n  font-family: sans-serif;\r\n  -ms-text-size-adjust: 100%;\r\n  -webkit-text-size-adjust: 100%;\r\n}\r\nbody {\r\n  margin: 0;\r\n}\r\narticle,\r\naside,\r\ndetails,\r\nfigcaption,\r\nfigure,\r\nfooter,\r\nheader,\r\nhgroup,\r\nmain,\r\nmenu,\r\nnav,\r\nsection,\r\nsummary {\r\n  display: block;\r\n}\r\naudio,\r\ncanvas,\r\nprogress,\r\nvideo {\r\n  display: inline-block;\r\n  vertical-align: baseline;\r\n}\r\naudio:not([controls]) {\r\n  display: none;\r\n  height: 0;\r\n}\r\n[hidden],\r\ntemplate {\r\n  display: none;\r\n}\r\na {\r\n  background-color: transparent;\r\n}\r\na:active,\r\na:hover {\r\n  outline: 0;\r\n}\r\nabbr[title] {\r\n  border-bottom: 1px dotted;\r\n}\r\nb,\r\nstrong {\r\n  font-weight: bold;\r\n}\r\ndfn {\r\n  font-style: italic;\r\n}\r\nh1 {\r\n  font-size: 2em;\r\n  margin: 0.67em 0;\r\n}\r\nmark {\r\n  background: #ff0;\r\n  color: #000;\r\n}\r\nsmall {\r\n  font-size: 80%;\r\n}\r\nsub,\r\nsup {\r\n  font-size: 75%;\r\n  line-height: 0;\r\n  position: relative;\r\n  vertical-align: baseline;\r\n}\r\nsup {\r\n  top: -0.5em;\r\n}\r\nsub {\r\n  bottom: -0.25em;\r\n}\r\nimg {\r\n  border: 0;\r\n}\r\nsvg:not(:root) {\r\n  overflow: hidden;\r\n}\r\nfigure {\r\n  margin: 1em 40px;\r\n}\r\nhr {\r\n  -moz-box-sizing: content-box;\r\n  -webkit-box-sizing: content-box;\r\n          box-sizing: content-box;\r\n  height: 0;\r\n}\r\npre {\r\n  overflow: auto;\r\n}\r\ncode,\r\nkbd,\r\npre,\r\nsamp {\r\n  font-family: monospace, monospace;\r\n  font-size: 1em;\r\n}\r\nbutton,\r\ninput,\r\noptgroup,\r\nselect,\r\ntextarea {\r\n  color: inherit;\r\n  font: inherit;\r\n  margin: 0;\r\n}\r\nbutton {\r\n  overflow: visible;\r\n}\r\nbutton,\r\nselect {\r\n  text-transform: none;\r\n}\r\nbutton,\r\nhtml input[type=\"button\"],\r\ninput[type=\"reset\"],\r\ninput[type=\"submit\"] {\r\n  -webkit-appearance: button;\r\n  cursor: pointer;\r\n}\r\nbutton[disabled],\r\nhtml input[disabled] {\r\n  cursor: default;\r\n}\r\nbutton::-moz-focus-inner,\r\ninput::-moz-focus-inner {\r\n  border: 0;\r\n  padding: 0;\r\n}\r\ninput {\r\n  line-height: normal;\r\n}\r\ninput[type=\"checkbox\"],\r\ninput[type=\"radio\"] {\r\n  -webkit-box-sizing: border-box;\r\n     -moz-box-sizing: border-box;\r\n          box-sizing: border-box;\r\n  padding: 0;\r\n}\r\ninput[type=\"number\"]::-webkit-inner-spin-button,\r\ninput[type=\"number\"]::-webkit-outer-spin-button {\r\n  height: auto;\r\n}\r\ninput[type=\"search\"] {\r\n  -webkit-appearance: textfield;\r\n  -moz-box-sizing: content-box;\r\n  -webkit-box-sizing: content-box;\r\n  box-sizing: content-box;\r\n}\r\ninput[type=\"search\"]::-webkit-search-cancel-button,\r\ninput[type=\"search\"]::-webkit-search-decoration {\r\n  -webkit-appearance: none;\r\n}\r\nfieldset {\r\n  border: 1px solid #c0c0c0;\r\n  margin: 0 2px;\r\n  padding: 0.35em 0.625em 0.75em;\r\n}\r\nlegend {\r\n  border: 0;\r\n  padding: 0;\r\n}\r\ntextarea {\r\n  overflow: auto;\r\n}\r\noptgroup {\r\n  font-weight: bold;\r\n}\r\ntable {\r\n  border-collapse: collapse;\r\n  border-spacing: 0;\r\n}\r\ntd,\r\nth {\r\n  padding: 0;\r\n}\r\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\r\n@media print {\r\n  *,\r\n  *:before,\r\n  *:after {\r\n    background: transparent !important;\r\n    color: #000 !important;\r\n    -webkit-box-shadow: none !important;\r\n            box-shadow: none !important;\r\n    text-shadow: none !important;\r\n  }\r\n  a,\r\n  a:visited {\r\n    text-decoration: underline;\r\n  }\r\n  a[href]:after {\r\n    content: \" (\" attr(href) \")\";\r\n  }\r\n  abbr[title]:after {\r\n    content: \" (\" attr(title) \")\";\r\n  }\r\n  a[href^=\"#\"]:after,\r\n  a[href^=\"javascript:\"]:after {\r\n    content: \"\";\r\n  }\r\n  pre,\r\n  blockquote {\r\n    border: 1px solid #999;\r\n    page-break-inside: avoid;\r\n  }\r\n  thead {\r\n    display: table-header-group;\r\n  }\r\n  tr,\r\n  img {\r\n    page-break-inside: avoid;\r\n  }\r\n  img {\r\n    max-width: 100% !important;\r\n  }\r\n  p,\r\n  h2,\r\n  h3 {\r\n    orphans: 3;\r\n    widows: 3;\r\n  }\r\n  h2,\r\n  h3 {\r\n    page-break-after: avoid;\r\n  }\r\n  select {\r\n    background: #fff !important;\r\n  }\r\n  .navbar {\r\n    display: none;\r\n  }\r\n  .btn > .caret,\r\n  .dropup > .btn > .caret {\r\n    border-top-color: #000 !important;\r\n  }\r\n  .label {\r\n    border: 1px solid #000;\r\n  }\r\n  .table {\r\n    border-collapse: collapse !important;\r\n  }\r\n  .table td,\r\n  .table th {\r\n    background-color: #fff !important;\r\n  }\r\n  .table-bordered th,\r\n  .table-bordered td {\r\n    border: 1px solid #ddd !important;\r\n  }\r\n}\r\n\r\n* {\r\n  -webkit-box-sizing: border-box;\r\n  -moz-box-sizing: border-box;\r\n  box-sizing: border-box;\r\n}\r\n*:before,\r\n*:after {\r\n  -webkit-box-sizing: border-box;\r\n  -moz-box-sizing: border-box;\r\n  box-sizing: border-box;\r\n}\r\nhtml {\r\n  font-size: 10px;\r\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\r\n}\r\nbody {\r\n  font-family: \"Lato\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\r\n  font-size: 15px;\r\n  line-height: 1.42857143;\r\n  color: #ebebeb;\r\n  background-color: #2b3e50;\r\n}\r\ninput,\r\nbutton,\r\nselect,\r\ntextarea {\r\n  font-family: inherit;\r\n  font-size: inherit;\r\n  line-height: inherit;\r\n}\r\na {\r\n  color: #df691a;\r\n  text-decoration: none;\r\n}\r\na:hover,\r\na:focus {\r\n  color: #df691a;\r\n  text-decoration: underline;\r\n}\r\na:focus {\r\n  outline: thin dotted;\r\n  outline: 5px auto -webkit-focus-ring-color;\r\n  outline-offset: -2px;\r\n}\r\nfigure {\r\n  margin: 0;\r\n}\r\nimg {\r\n  vertical-align: middle;\r\n}\r\n.img-responsive,\r\n.thumbnail > img,\r\n.thumbnail a > img,\r\n.carousel-inner > .item > img,\r\n.carousel-inner > .item > a > img {\r\n  display: block;\r\n  max-width: 100%;\r\n  height: auto;\r\n}\r\n.img-rounded {\r\n  border-radius: 0;\r\n}\r\n.img-thumbnail {\r\n  padding: 4px;\r\n  line-height: 1.42857143;\r\n  background-color: #2b3e50;\r\n  border: 1px solid #dddddd;\r\n  border-radius: 0;\r\n  -webkit-transition: all 0.2s ease-in-out;\r\n  -o-transition: all 0.2s ease-in-out;\r\n  transition: all 0.2s ease-in-out;\r\n  display: inline-block;\r\n  max-width: 100%;\r\n  height: auto;\r\n}\r\n.img-circle {\r\n  border-radius: 50%;\r\n}\r\nhr {\r\n  margin-top: 21px;\r\n  margin-bottom: 21px;\r\n  border: 0;\r\n  border-top: 1px solid #596a7b;\r\n}\r\n.sr-only {\r\n  position: absolute;\r\n  width: 1px;\r\n  height: 1px;\r\n  margin: -1px;\r\n  padding: 0;\r\n  overflow: hidden;\r\n  clip: rect(0, 0, 0, 0);\r\n  border: 0;\r\n}\r\n.sr-only-focusable:active,\r\n.sr-only-focusable:focus {\r\n  position: static;\r\n  width: auto;\r\n  height: auto;\r\n  margin: 0;\r\n  overflow: visible;\r\n  clip: auto;\r\n}\r\n[role=\"button\"] {\r\n  cursor: pointer;\r\n}\r\nh1,\r\nh2,\r\nh3,\r\nh4,\r\nh5,\r\nh6,\r\n.h1,\r\n.h2,\r\n.h3,\r\n.h4,\r\n.h5,\r\n.h6 {\r\n  font-family: inherit;\r\n  font-weight: 300;\r\n  line-height: 1.1;\r\n  color: inherit;\r\n}\r\nh1 small,\r\nh2 small,\r\nh3 small,\r\nh4 small,\r\nh5 small,\r\nh6 small,\r\n.h1 small,\r\n.h2 small,\r\n.h3 small,\r\n.h4 small,\r\n.h5 small,\r\n.h6 small,\r\nh1 .small,\r\nh2 .small,\r\nh3 .small,\r\nh4 .small,\r\nh5 .small,\r\nh6 .small,\r\n.h1 .small,\r\n.h2 .small,\r\n.h3 .small,\r\n.h4 .small,\r\n.h5 .small,\r\n.h6 .small {\r\n  font-weight: normal;\r\n  line-height: 1;\r\n  color: #ebebeb;\r\n}\r\nh1,\r\n.h1,\r\nh2,\r\n.h2,\r\nh3,\r\n.h3 {\r\n  margin-top: 21px;\r\n  margin-bottom: 10.5px;\r\n}\r\nh1 small,\r\n.h1 small,\r\nh2 small,\r\n.h2 small,\r\nh3 small,\r\n.h3 small,\r\nh1 .small,\r\n.h1 .small,\r\nh2 .small,\r\n.h2 .small,\r\nh3 .small,\r\n.h3 .small {\r\n  font-size: 65%;\r\n}\r\nh4,\r\n.h4,\r\nh5,\r\n.h5,\r\nh6,\r\n.h6 {\r\n  margin-top: 10.5px;\r\n  margin-bottom: 10.5px;\r\n}\r\nh4 small,\r\n.h4 small,\r\nh5 small,\r\n.h5 small,\r\nh6 small,\r\n.h6 small,\r\nh4 .small,\r\n.h4 .small,\r\nh5 .small,\r\n.h5 .small,\r\nh6 .small,\r\n.h6 .small {\r\n  font-size: 75%;\r\n}\r\nh1,\r\n.h1 {\r\n  font-size: 39px;\r\n}\r\nh2,\r\n.h2 {\r\n  font-size: 32px;\r\n}\r\nh3,\r\n.h3 {\r\n  font-size: 26px;\r\n}\r\nh4,\r\n.h4 {\r\n  font-size: 19px;\r\n}\r\nh5,\r\n.h5 {\r\n  font-size: 15px;\r\n}\r\nh6,\r\n.h6 {\r\n  font-size: 13px;\r\n}\r\np {\r\n  margin: 0 0 10.5px;\r\n}\r\n.lead {\r\n  margin-bottom: 21px;\r\n  font-size: 17px;\r\n  font-weight: 300;\r\n  line-height: 1.4;\r\n}\r\n@media (min-width: 768px) {\r\n  .lead {\r\n    font-size: 22.5px;\r\n  }\r\n}\r\nsmall,\r\n.small {\r\n  font-size: 86%;\r\n}\r\nmark,\r\n.mark {\r\n  background-color: #f0ad4e;\r\n  padding: .2em;\r\n}\r\n.text-left {\r\n  text-align: left;\r\n}\r\n.text-right {\r\n  text-align: right;\r\n}\r\n.text-center {\r\n  text-align: center;\r\n}\r\n.text-justify {\r\n  text-align: justify;\r\n}\r\n.text-nowrap {\r\n  white-space: nowrap;\r\n}\r\n.text-lowercase {\r\n  text-transform: lowercase;\r\n}\r\n.text-uppercase {\r\n  text-transform: uppercase;\r\n}\r\n.text-capitalize {\r\n  text-transform: capitalize;\r\n}\r\n.text-muted {\r\n  color: #4e5d6c;\r\n}\r\n.text-primary {\r\n  color: #df691a;\r\n}\r\na.text-primary:hover {\r\n  color: #b15315;\r\n}\r\n.text-success {\r\n  color: #ebebeb;\r\n}\r\na.text-success:hover {\r\n  color: #d2d2d2;\r\n}\r\n.text-info {\r\n  color: #ebebeb;\r\n}\r\na.text-info:hover {\r\n  color: #d2d2d2;\r\n}\r\n.text-warning {\r\n  color: #ebebeb;\r\n}\r\na.text-warning:hover {\r\n  color: #d2d2d2;\r\n}\r\n.text-danger {\r\n  color: #ebebeb;\r\n}\r\na.text-danger:hover {\r\n  color: #d2d2d2;\r\n}\r\n.bg-primary {\r\n  color: #fff;\r\n  background-color: #df691a;\r\n}\r\na.bg-primary:hover {\r\n  background-color: #b15315;\r\n}\r\n.bg-success {\r\n  background-color: #5cb85c;\r\n}\r\na.bg-success:hover {\r\n  background-color: #449d44;\r\n}\r\n.bg-info {\r\n  background-color: #5bc0de;\r\n}\r\na.bg-info:hover {\r\n  background-color: #31b0d5;\r\n}\r\n.bg-warning {\r\n  background-color: #f0ad4e;\r\n}\r\na.bg-warning:hover {\r\n  background-color: #ec971f;\r\n}\r\n.bg-danger {\r\n  background-color: #d9534f;\r\n}\r\na.bg-danger:hover {\r\n  background-color: #c9302c;\r\n}\r\n.page-header {\r\n  padding-bottom: 9.5px;\r\n  margin: 42px 0 21px;\r\n  border-bottom: 1px solid #ebebeb;\r\n}\r\nul,\r\nol {\r\n  margin-top: 0;\r\n  margin-bottom: 10.5px;\r\n}\r\nul ul,\r\nol ul,\r\nul ol,\r\nol ol {\r\n  margin-bottom: 0;\r\n}\r\n.list-unstyled {\r\n  padding-left: 0;\r\n  list-style: none;\r\n}\r\n.list-inline {\r\n  padding-left: 0;\r\n  list-style: none;\r\n  margin-left: -5px;\r\n}\r\n.list-inline > li {\r\n  display: inline-block;\r\n  padding-left: 5px;\r\n  padding-right: 5px;\r\n}\r\ndl {\r\n  margin-top: 0;\r\n  margin-bottom: 21px;\r\n}\r\ndt,\r\ndd {\r\n  line-height: 1.42857143;\r\n}\r\ndt {\r\n  font-weight: bold;\r\n}\r\ndd {\r\n  margin-left: 0;\r\n}\r\n@media (min-width: 768px) {\r\n  .dl-horizontal dt {\r\n    float: left;\r\n    width: 160px;\r\n    clear: left;\r\n    text-align: right;\r\n    overflow: hidden;\r\n    text-overflow: ellipsis;\r\n    white-space: nowrap;\r\n  }\r\n  .dl-horizontal dd {\r\n    margin-left: 180px;\r\n  }\r\n}\r\nabbr[title],\r\nabbr[data-original-title] {\r\n  cursor: help;\r\n  border-bottom: 1px dotted #4e5d6c;\r\n}\r\n.initialism {\r\n  font-size: 90%;\r\n  text-transform: uppercase;\r\n}\r\nblockquote {\r\n  padding: 10.5px 21px;\r\n  margin: 0 0 21px;\r\n  font-size: 18.75px;\r\n  border-left: 5px solid #4e5d6c;\r\n}\r\nblockquote p:last-child,\r\nblockquote ul:last-child,\r\nblockquote ol:last-child {\r\n  margin-bottom: 0;\r\n}\r\nblockquote footer,\r\nblockquote small,\r\nblockquote .small {\r\n  display: block;\r\n  font-size: 80%;\r\n  line-height: 1.42857143;\r\n  color: #ebebeb;\r\n}\r\nblockquote footer:before,\r\nblockquote small:before,\r\nblockquote .small:before {\r\n  content: '\\2014 \\00A0';\r\n}\r\n.blockquote-reverse,\r\nblockquote.pull-right {\r\n  padding-right: 15px;\r\n  padding-left: 0;\r\n  border-right: 5px solid #4e5d6c;\r\n  border-left: 0;\r\n  text-align: right;\r\n}\r\n.blockquote-reverse footer:before,\r\nblockquote.pull-right footer:before,\r\n.blockquote-reverse small:before,\r\nblockquote.pull-right small:before,\r\n.blockquote-reverse .small:before,\r\nblockquote.pull-right .small:before {\r\n  content: '';\r\n}\r\n.blockquote-reverse footer:after,\r\nblockquote.pull-right footer:after,\r\n.blockquote-reverse small:after,\r\nblockquote.pull-right small:after,\r\n.blockquote-reverse .small:after,\r\nblockquote.pull-right .small:after {\r\n  content: '\\00A0 \\2014';\r\n}\r\naddress {\r\n  margin-bottom: 21px;\r\n  font-style: normal;\r\n  line-height: 1.42857143;\r\n}\r\ncode,\r\nkbd,\r\npre,\r\nsamp {\r\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\r\n}\r\ncode {\r\n  padding: 2px 4px;\r\n  font-size: 90%;\r\n  color: #c7254e;\r\n  background-color: #f9f2f4;\r\n  border-radius: 0;\r\n}\r\nkbd {\r\n  padding: 2px 4px;\r\n  font-size: 90%;\r\n  color: #ffffff;\r\n  background-color: #333333;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\r\n          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\r\n}\r\nkbd kbd {\r\n  padding: 0;\r\n  font-size: 100%;\r\n  font-weight: bold;\r\n  -webkit-box-shadow: none;\r\n          box-shadow: none;\r\n}\r\npre {\r\n  display: block;\r\n  padding: 10px;\r\n  margin: 0 0 10.5px;\r\n  font-size: 14px;\r\n  line-height: 1.42857143;\r\n  word-break: break-all;\r\n  word-wrap: break-word;\r\n  color: #333333;\r\n  background-color: #f5f5f5;\r\n  border: 1px solid #cccccc;\r\n  border-radius: 0;\r\n}\r\npre code {\r\n  padding: 0;\r\n  font-size: inherit;\r\n  color: inherit;\r\n  white-space: pre-wrap;\r\n  background-color: transparent;\r\n  border-radius: 0;\r\n}\r\n.pre-scrollable {\r\n  max-height: 340px;\r\n  overflow-y: scroll;\r\n}\r\n.container {\r\n  margin-right: auto;\r\n  margin-left: auto;\r\n  padding-left: 15px;\r\n  padding-right: 15px;\r\n}\r\n@media (min-width: 768px) {\r\n  .container {\r\n    width: 750px;\r\n  }\r\n}\r\n@media (min-width: 992px) {\r\n  .container {\r\n    width: 970px;\r\n  }\r\n}\r\n@media (min-width: 1200px) {\r\n  .container {\r\n    width: 1170px;\r\n  }\r\n}\r\n.container-fluid {\r\n  margin-right: auto;\r\n  margin-left: auto;\r\n  padding-left: 15px;\r\n  padding-right: 15px;\r\n}\r\n.row {\r\n  margin-left: -15px;\r\n  margin-right: -15px;\r\n}\r\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\r\n  position: relative;\r\n  min-height: 1px;\r\n  padding-left: 15px;\r\n  padding-right: 15px;\r\n}\r\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\r\n  float: left;\r\n}\r\n.col-xs-12 {\r\n  width: 100%;\r\n}\r\n.col-xs-11 {\r\n  width: 91.66666667%;\r\n}\r\n.col-xs-10 {\r\n  width: 83.33333333%;\r\n}\r\n.col-xs-9 {\r\n  width: 75%;\r\n}\r\n.col-xs-8 {\r\n  width: 66.66666667%;\r\n}\r\n.col-xs-7 {\r\n  width: 58.33333333%;\r\n}\r\n.col-xs-6 {\r\n  width: 50%;\r\n}\r\n.col-xs-5 {\r\n  width: 41.66666667%;\r\n}\r\n.col-xs-4 {\r\n  width: 33.33333333%;\r\n}\r\n.col-xs-3 {\r\n  width: 25%;\r\n}\r\n.col-xs-2 {\r\n  width: 16.66666667%;\r\n}\r\n.col-xs-1 {\r\n  width: 8.33333333%;\r\n}\r\n.col-xs-pull-12 {\r\n  right: 100%;\r\n}\r\n.col-xs-pull-11 {\r\n  right: 91.66666667%;\r\n}\r\n.col-xs-pull-10 {\r\n  right: 83.33333333%;\r\n}\r\n.col-xs-pull-9 {\r\n  right: 75%;\r\n}\r\n.col-xs-pull-8 {\r\n  right: 66.66666667%;\r\n}\r\n.col-xs-pull-7 {\r\n  right: 58.33333333%;\r\n}\r\n.col-xs-pull-6 {\r\n  right: 50%;\r\n}\r\n.col-xs-pull-5 {\r\n  right: 41.66666667%;\r\n}\r\n.col-xs-pull-4 {\r\n  right: 33.33333333%;\r\n}\r\n.col-xs-pull-3 {\r\n  right: 25%;\r\n}\r\n.col-xs-pull-2 {\r\n  right: 16.66666667%;\r\n}\r\n.col-xs-pull-1 {\r\n  right: 8.33333333%;\r\n}\r\n.col-xs-pull-0 {\r\n  right: auto;\r\n}\r\n.col-xs-push-12 {\r\n  left: 100%;\r\n}\r\n.col-xs-push-11 {\r\n  left: 91.66666667%;\r\n}\r\n.col-xs-push-10 {\r\n  left: 83.33333333%;\r\n}\r\n.col-xs-push-9 {\r\n  left: 75%;\r\n}\r\n.col-xs-push-8 {\r\n  left: 66.66666667%;\r\n}\r\n.col-xs-push-7 {\r\n  left: 58.33333333%;\r\n}\r\n.col-xs-push-6 {\r\n  left: 50%;\r\n}\r\n.col-xs-push-5 {\r\n  left: 41.66666667%;\r\n}\r\n.col-xs-push-4 {\r\n  left: 33.33333333%;\r\n}\r\n.col-xs-push-3 {\r\n  left: 25%;\r\n}\r\n.col-xs-push-2 {\r\n  left: 16.66666667%;\r\n}\r\n.col-xs-push-1 {\r\n  left: 8.33333333%;\r\n}\r\n.col-xs-push-0 {\r\n  left: auto;\r\n}\r\n.col-xs-offset-12 {\r\n  margin-left: 100%;\r\n}\r\n.col-xs-offset-11 {\r\n  margin-left: 91.66666667%;\r\n}\r\n.col-xs-offset-10 {\r\n  margin-left: 83.33333333%;\r\n}\r\n.col-xs-offset-9 {\r\n  margin-left: 75%;\r\n}\r\n.col-xs-offset-8 {\r\n  margin-left: 66.66666667%;\r\n}\r\n.col-xs-offset-7 {\r\n  margin-left: 58.33333333%;\r\n}\r\n.col-xs-offset-6 {\r\n  margin-left: 50%;\r\n}\r\n.col-xs-offset-5 {\r\n  margin-left: 41.66666667%;\r\n}\r\n.col-xs-offset-4 {\r\n  margin-left: 33.33333333%;\r\n}\r\n.col-xs-offset-3 {\r\n  margin-left: 25%;\r\n}\r\n.col-xs-offset-2 {\r\n  margin-left: 16.66666667%;\r\n}\r\n.col-xs-offset-1 {\r\n  margin-left: 8.33333333%;\r\n}\r\n.col-xs-offset-0 {\r\n  margin-left: 0%;\r\n}\r\n@media (min-width: 768px) {\r\n  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\r\n    float: left;\r\n  }\r\n  .col-sm-12 {\r\n    width: 100%;\r\n  }\r\n  .col-sm-11 {\r\n    width: 91.66666667%;\r\n  }\r\n  .col-sm-10 {\r\n    width: 83.33333333%;\r\n  }\r\n  .col-sm-9 {\r\n    width: 75%;\r\n  }\r\n  .col-sm-8 {\r\n    width: 66.66666667%;\r\n  }\r\n  .col-sm-7 {\r\n    width: 58.33333333%;\r\n  }\r\n  .col-sm-6 {\r\n    width: 50%;\r\n  }\r\n  .col-sm-5 {\r\n    width: 41.66666667%;\r\n  }\r\n  .col-sm-4 {\r\n    width: 33.33333333%;\r\n  }\r\n  .col-sm-3 {\r\n    width: 25%;\r\n  }\r\n  .col-sm-2 {\r\n    width: 16.66666667%;\r\n  }\r\n  .col-sm-1 {\r\n    width: 8.33333333%;\r\n  }\r\n  .col-sm-pull-12 {\r\n    right: 100%;\r\n  }\r\n  .col-sm-pull-11 {\r\n    right: 91.66666667%;\r\n  }\r\n  .col-sm-pull-10 {\r\n    right: 83.33333333%;\r\n  }\r\n  .col-sm-pull-9 {\r\n    right: 75%;\r\n  }\r\n  .col-sm-pull-8 {\r\n    right: 66.66666667%;\r\n  }\r\n  .col-sm-pull-7 {\r\n    right: 58.33333333%;\r\n  }\r\n  .col-sm-pull-6 {\r\n    right: 50%;\r\n  }\r\n  .col-sm-pull-5 {\r\n    right: 41.66666667%;\r\n  }\r\n  .col-sm-pull-4 {\r\n    right: 33.33333333%;\r\n  }\r\n  .col-sm-pull-3 {\r\n    right: 25%;\r\n  }\r\n  .col-sm-pull-2 {\r\n    right: 16.66666667%;\r\n  }\r\n  .col-sm-pull-1 {\r\n    right: 8.33333333%;\r\n  }\r\n  .col-sm-pull-0 {\r\n    right: auto;\r\n  }\r\n  .col-sm-push-12 {\r\n    left: 100%;\r\n  }\r\n  .col-sm-push-11 {\r\n    left: 91.66666667%;\r\n  }\r\n  .col-sm-push-10 {\r\n    left: 83.33333333%;\r\n  }\r\n  .col-sm-push-9 {\r\n    left: 75%;\r\n  }\r\n  .col-sm-push-8 {\r\n    left: 66.66666667%;\r\n  }\r\n  .col-sm-push-7 {\r\n    left: 58.33333333%;\r\n  }\r\n  .col-sm-push-6 {\r\n    left: 50%;\r\n  }\r\n  .col-sm-push-5 {\r\n    left: 41.66666667%;\r\n  }\r\n  .col-sm-push-4 {\r\n    left: 33.33333333%;\r\n  }\r\n  .col-sm-push-3 {\r\n    left: 25%;\r\n  }\r\n  .col-sm-push-2 {\r\n    left: 16.66666667%;\r\n  }\r\n  .col-sm-push-1 {\r\n    left: 8.33333333%;\r\n  }\r\n  .col-sm-push-0 {\r\n    left: auto;\r\n  }\r\n  .col-sm-offset-12 {\r\n    margin-left: 100%;\r\n  }\r\n  .col-sm-offset-11 {\r\n    margin-left: 91.66666667%;\r\n  }\r\n  .col-sm-offset-10 {\r\n    margin-left: 83.33333333%;\r\n  }\r\n  .col-sm-offset-9 {\r\n    margin-left: 75%;\r\n  }\r\n  .col-sm-offset-8 {\r\n    margin-left: 66.66666667%;\r\n  }\r\n  .col-sm-offset-7 {\r\n    margin-left: 58.33333333%;\r\n  }\r\n  .col-sm-offset-6 {\r\n    margin-left: 50%;\r\n  }\r\n  .col-sm-offset-5 {\r\n    margin-left: 41.66666667%;\r\n  }\r\n  .col-sm-offset-4 {\r\n    margin-left: 33.33333333%;\r\n  }\r\n  .col-sm-offset-3 {\r\n    margin-left: 25%;\r\n  }\r\n  .col-sm-offset-2 {\r\n    margin-left: 16.66666667%;\r\n  }\r\n  .col-sm-offset-1 {\r\n    margin-left: 8.33333333%;\r\n  }\r\n  .col-sm-offset-0 {\r\n    margin-left: 0%;\r\n  }\r\n}\r\n@media (min-width: 992px) {\r\n  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\r\n    float: left;\r\n  }\r\n  .col-md-12 {\r\n    width: 100%;\r\n  }\r\n  .col-md-11 {\r\n    width: 91.66666667%;\r\n  }\r\n  .col-md-10 {\r\n    width: 83.33333333%;\r\n  }\r\n  .col-md-9 {\r\n    width: 75%;\r\n  }\r\n  .col-md-8 {\r\n    width: 66.66666667%;\r\n  }\r\n  .col-md-7 {\r\n    width: 58.33333333%;\r\n  }\r\n  .col-md-6 {\r\n    width: 50%;\r\n  }\r\n  .col-md-5 {\r\n    width: 41.66666667%;\r\n  }\r\n  .col-md-4 {\r\n    width: 33.33333333%;\r\n  }\r\n  .col-md-3 {\r\n    width: 25%;\r\n  }\r\n  .col-md-2 {\r\n    width: 16.66666667%;\r\n  }\r\n  .col-md-1 {\r\n    width: 8.33333333%;\r\n  }\r\n  .col-md-pull-12 {\r\n    right: 100%;\r\n  }\r\n  .col-md-pull-11 {\r\n    right: 91.66666667%;\r\n  }\r\n  .col-md-pull-10 {\r\n    right: 83.33333333%;\r\n  }\r\n  .col-md-pull-9 {\r\n    right: 75%;\r\n  }\r\n  .col-md-pull-8 {\r\n    right: 66.66666667%;\r\n  }\r\n  .col-md-pull-7 {\r\n    right: 58.33333333%;\r\n  }\r\n  .col-md-pull-6 {\r\n    right: 50%;\r\n  }\r\n  .col-md-pull-5 {\r\n    right: 41.66666667%;\r\n  }\r\n  .col-md-pull-4 {\r\n    right: 33.33333333%;\r\n  }\r\n  .col-md-pull-3 {\r\n    right: 25%;\r\n  }\r\n  .col-md-pull-2 {\r\n    right: 16.66666667%;\r\n  }\r\n  .col-md-pull-1 {\r\n    right: 8.33333333%;\r\n  }\r\n  .col-md-pull-0 {\r\n    right: auto;\r\n  }\r\n  .col-md-push-12 {\r\n    left: 100%;\r\n  }\r\n  .col-md-push-11 {\r\n    left: 91.66666667%;\r\n  }\r\n  .col-md-push-10 {\r\n    left: 83.33333333%;\r\n  }\r\n  .col-md-push-9 {\r\n    left: 75%;\r\n  }\r\n  .col-md-push-8 {\r\n    left: 66.66666667%;\r\n  }\r\n  .col-md-push-7 {\r\n    left: 58.33333333%;\r\n  }\r\n  .col-md-push-6 {\r\n    left: 50%;\r\n  }\r\n  .col-md-push-5 {\r\n    left: 41.66666667%;\r\n  }\r\n  .col-md-push-4 {\r\n    left: 33.33333333%;\r\n  }\r\n  .col-md-push-3 {\r\n    left: 25%;\r\n  }\r\n  .col-md-push-2 {\r\n    left: 16.66666667%;\r\n  }\r\n  .col-md-push-1 {\r\n    left: 8.33333333%;\r\n  }\r\n  .col-md-push-0 {\r\n    left: auto;\r\n  }\r\n  .col-md-offset-12 {\r\n    margin-left: 100%;\r\n  }\r\n  .col-md-offset-11 {\r\n    margin-left: 91.66666667%;\r\n  }\r\n  .col-md-offset-10 {\r\n    margin-left: 83.33333333%;\r\n  }\r\n  .col-md-offset-9 {\r\n    margin-left: 75%;\r\n  }\r\n  .col-md-offset-8 {\r\n    margin-left: 66.66666667%;\r\n  }\r\n  .col-md-offset-7 {\r\n    margin-left: 58.33333333%;\r\n  }\r\n  .col-md-offset-6 {\r\n    margin-left: 50%;\r\n  }\r\n  .col-md-offset-5 {\r\n    margin-left: 41.66666667%;\r\n  }\r\n  .col-md-offset-4 {\r\n    margin-left: 33.33333333%;\r\n  }\r\n  .col-md-offset-3 {\r\n    margin-left: 25%;\r\n  }\r\n  .col-md-offset-2 {\r\n    margin-left: 16.66666667%;\r\n  }\r\n  .col-md-offset-1 {\r\n    margin-left: 8.33333333%;\r\n  }\r\n  .col-md-offset-0 {\r\n    margin-left: 0%;\r\n  }\r\n}\r\n@media (min-width: 1200px) {\r\n  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\r\n    float: left;\r\n  }\r\n  .col-lg-12 {\r\n    width: 100%;\r\n  }\r\n  .col-lg-11 {\r\n    width: 91.66666667%;\r\n  }\r\n  .col-lg-10 {\r\n    width: 83.33333333%;\r\n  }\r\n  .col-lg-9 {\r\n    width: 75%;\r\n  }\r\n  .col-lg-8 {\r\n    width: 66.66666667%;\r\n  }\r\n  .col-lg-7 {\r\n    width: 58.33333333%;\r\n  }\r\n  .col-lg-6 {\r\n    width: 50%;\r\n  }\r\n  .col-lg-5 {\r\n    width: 41.66666667%;\r\n  }\r\n  .col-lg-4 {\r\n    width: 33.33333333%;\r\n  }\r\n  .col-lg-3 {\r\n    width: 25%;\r\n  }\r\n  .col-lg-2 {\r\n    width: 16.66666667%;\r\n  }\r\n  .col-lg-1 {\r\n    width: 8.33333333%;\r\n  }\r\n  .col-lg-pull-12 {\r\n    right: 100%;\r\n  }\r\n  .col-lg-pull-11 {\r\n    right: 91.66666667%;\r\n  }\r\n  .col-lg-pull-10 {\r\n    right: 83.33333333%;\r\n  }\r\n  .col-lg-pull-9 {\r\n    right: 75%;\r\n  }\r\n  .col-lg-pull-8 {\r\n    right: 66.66666667%;\r\n  }\r\n  .col-lg-pull-7 {\r\n    right: 58.33333333%;\r\n  }\r\n  .col-lg-pull-6 {\r\n    right: 50%;\r\n  }\r\n  .col-lg-pull-5 {\r\n    right: 41.66666667%;\r\n  }\r\n  .col-lg-pull-4 {\r\n    right: 33.33333333%;\r\n  }\r\n  .col-lg-pull-3 {\r\n    right: 25%;\r\n  }\r\n  .col-lg-pull-2 {\r\n    right: 16.66666667%;\r\n  }\r\n  .col-lg-pull-1 {\r\n    right: 8.33333333%;\r\n  }\r\n  .col-lg-pull-0 {\r\n    right: auto;\r\n  }\r\n  .col-lg-push-12 {\r\n    left: 100%;\r\n  }\r\n  .col-lg-push-11 {\r\n    left: 91.66666667%;\r\n  }\r\n  .col-lg-push-10 {\r\n    left: 83.33333333%;\r\n  }\r\n  .col-lg-push-9 {\r\n    left: 75%;\r\n  }\r\n  .col-lg-push-8 {\r\n    left: 66.66666667%;\r\n  }\r\n  .col-lg-push-7 {\r\n    left: 58.33333333%;\r\n  }\r\n  .col-lg-push-6 {\r\n    left: 50%;\r\n  }\r\n  .col-lg-push-5 {\r\n    left: 41.66666667%;\r\n  }\r\n  .col-lg-push-4 {\r\n    left: 33.33333333%;\r\n  }\r\n  .col-lg-push-3 {\r\n    left: 25%;\r\n  }\r\n  .col-lg-push-2 {\r\n    left: 16.66666667%;\r\n  }\r\n  .col-lg-push-1 {\r\n    left: 8.33333333%;\r\n  }\r\n  .col-lg-push-0 {\r\n    left: auto;\r\n  }\r\n  .col-lg-offset-12 {\r\n    margin-left: 100%;\r\n  }\r\n  .col-lg-offset-11 {\r\n    margin-left: 91.66666667%;\r\n  }\r\n  .col-lg-offset-10 {\r\n    margin-left: 83.33333333%;\r\n  }\r\n  .col-lg-offset-9 {\r\n    margin-left: 75%;\r\n  }\r\n  .col-lg-offset-8 {\r\n    margin-left: 66.66666667%;\r\n  }\r\n  .col-lg-offset-7 {\r\n    margin-left: 58.33333333%;\r\n  }\r\n  .col-lg-offset-6 {\r\n    margin-left: 50%;\r\n  }\r\n  .col-lg-offset-5 {\r\n    margin-left: 41.66666667%;\r\n  }\r\n  .col-lg-offset-4 {\r\n    margin-left: 33.33333333%;\r\n  }\r\n  .col-lg-offset-3 {\r\n    margin-left: 25%;\r\n  }\r\n  .col-lg-offset-2 {\r\n    margin-left: 16.66666667%;\r\n  }\r\n  .col-lg-offset-1 {\r\n    margin-left: 8.33333333%;\r\n  }\r\n  .col-lg-offset-0 {\r\n    margin-left: 0%;\r\n  }\r\n}\r\ntable {\r\n  background-color: transparent;\r\n}\r\ncaption {\r\n  padding-top: 6px;\r\n  padding-bottom: 6px;\r\n  color: #4e5d6c;\r\n  text-align: left;\r\n}\r\nth {\r\n  text-align: left;\r\n}\r\n.table {\r\n  width: 100%;\r\n  max-width: 100%;\r\n  margin-bottom: 21px;\r\n}\r\n.table > thead > tr > th,\r\n.table > tbody > tr > th,\r\n.table > tfoot > tr > th,\r\n.table > thead > tr > td,\r\n.table > tbody > tr > td,\r\n.table > tfoot > tr > td {\r\n  padding: 10px;\r\n  line-height: 1.42857143;\r\n  vertical-align: top;\r\n  border-top: 1px solid #4e5d6c;\r\n}\r\n.table > thead > tr > th {\r\n  vertical-align: bottom;\r\n  border-bottom: 2px solid #4e5d6c;\r\n}\r\n.table > caption + thead > tr:first-child > th,\r\n.table > colgroup + thead > tr:first-child > th,\r\n.table > thead:first-child > tr:first-child > th,\r\n.table > caption + thead > tr:first-child > td,\r\n.table > colgroup + thead > tr:first-child > td,\r\n.table > thead:first-child > tr:first-child > td {\r\n  border-top: 0;\r\n}\r\n.table > tbody + tbody {\r\n  border-top: 2px solid #4e5d6c;\r\n}\r\n.table .table {\r\n  background-color: #2b3e50;\r\n}\r\n.table-condensed > thead > tr > th,\r\n.table-condensed > tbody > tr > th,\r\n.table-condensed > tfoot > tr > th,\r\n.table-condensed > thead > tr > td,\r\n.table-condensed > tbody > tr > td,\r\n.table-condensed > tfoot > tr > td {\r\n  padding: 3px;\r\n}\r\n.table-bordered {\r\n  border: 1px solid #4e5d6c;\r\n}\r\n.table-bordered > thead > tr > th,\r\n.table-bordered > tbody > tr > th,\r\n.table-bordered > tfoot > tr > th,\r\n.table-bordered > thead > tr > td,\r\n.table-bordered > tbody > tr > td,\r\n.table-bordered > tfoot > tr > td {\r\n  border: 1px solid #4e5d6c;\r\n}\r\n.table-bordered > thead > tr > th,\r\n.table-bordered > thead > tr > td {\r\n  border-bottom-width: 2px;\r\n}\r\n.table-striped > tbody > tr:nth-of-type(odd) {\r\n  background-color: #4e5d6c;\r\n}\r\n.table-hover > tbody > tr:hover {\r\n  background-color: #485563;\r\n}\r\ntable col[class*=\"col-\"] {\r\n  position: static;\r\n  float: none;\r\n  display: table-column;\r\n}\r\ntable td[class*=\"col-\"],\r\ntable th[class*=\"col-\"] {\r\n  position: static;\r\n  float: none;\r\n  display: table-cell;\r\n}\r\n.table > thead > tr > td.active,\r\n.table > tbody > tr > td.active,\r\n.table > tfoot > tr > td.active,\r\n.table > thead > tr > th.active,\r\n.table > tbody > tr > th.active,\r\n.table > tfoot > tr > th.active,\r\n.table > thead > tr.active > td,\r\n.table > tbody > tr.active > td,\r\n.table > tfoot > tr.active > td,\r\n.table > thead > tr.active > th,\r\n.table > tbody > tr.active > th,\r\n.table > tfoot > tr.active > th {\r\n  background-color: #485563;\r\n}\r\n.table-hover > tbody > tr > td.active:hover,\r\n.table-hover > tbody > tr > th.active:hover,\r\n.table-hover > tbody > tr.active:hover > td,\r\n.table-hover > tbody > tr:hover > .active,\r\n.table-hover > tbody > tr.active:hover > th {\r\n  background-color: #3d4954;\r\n}\r\n.table > thead > tr > td.success,\r\n.table > tbody > tr > td.success,\r\n.table > tfoot > tr > td.success,\r\n.table > thead > tr > th.success,\r\n.table > tbody > tr > th.success,\r\n.table > tfoot > tr > th.success,\r\n.table > thead > tr.success > td,\r\n.table > tbody > tr.success > td,\r\n.table > tfoot > tr.success > td,\r\n.table > thead > tr.success > th,\r\n.table > tbody > tr.success > th,\r\n.table > tfoot > tr.success > th {\r\n  background-color: #5cb85c;\r\n}\r\n.table-hover > tbody > tr > td.success:hover,\r\n.table-hover > tbody > tr > th.success:hover,\r\n.table-hover > tbody > tr.success:hover > td,\r\n.table-hover > tbody > tr:hover > .success,\r\n.table-hover > tbody > tr.success:hover > th {\r\n  background-color: #4cae4c;\r\n}\r\n.table > thead > tr > td.info,\r\n.table > tbody > tr > td.info,\r\n.table > tfoot > tr > td.info,\r\n.table > thead > tr > th.info,\r\n.table > tbody > tr > th.info,\r\n.table > tfoot > tr > th.info,\r\n.table > thead > tr.info > td,\r\n.table > tbody > tr.info > td,\r\n.table > tfoot > tr.info > td,\r\n.table > thead > tr.info > th,\r\n.table > tbody > tr.info > th,\r\n.table > tfoot > tr.info > th {\r\n  background-color: #5bc0de;\r\n}\r\n.table-hover > tbody > tr > td.info:hover,\r\n.table-hover > tbody > tr > th.info:hover,\r\n.table-hover > tbody > tr.info:hover > td,\r\n.table-hover > tbody > tr:hover > .info,\r\n.table-hover > tbody > tr.info:hover > th {\r\n  background-color: #46b8da;\r\n}\r\n.table > thead > tr > td.warning,\r\n.table > tbody > tr > td.warning,\r\n.table > tfoot > tr > td.warning,\r\n.table > thead > tr > th.warning,\r\n.table > tbody > tr > th.warning,\r\n.table > tfoot > tr > th.warning,\r\n.table > thead > tr.warning > td,\r\n.table > tbody > tr.warning > td,\r\n.table > tfoot > tr.warning > td,\r\n.table > thead > tr.warning > th,\r\n.table > tbody > tr.warning > th,\r\n.table > tfoot > tr.warning > th {\r\n  background-color: #f0ad4e;\r\n}\r\n.table-hover > tbody > tr > td.warning:hover,\r\n.table-hover > tbody > tr > th.warning:hover,\r\n.table-hover > tbody > tr.warning:hover > td,\r\n.table-hover > tbody > tr:hover > .warning,\r\n.table-hover > tbody > tr.warning:hover > th {\r\n  background-color: #eea236;\r\n}\r\n.table > thead > tr > td.danger,\r\n.table > tbody > tr > td.danger,\r\n.table > tfoot > tr > td.danger,\r\n.table > thead > tr > th.danger,\r\n.table > tbody > tr > th.danger,\r\n.table > tfoot > tr > th.danger,\r\n.table > thead > tr.danger > td,\r\n.table > tbody > tr.danger > td,\r\n.table > tfoot > tr.danger > td,\r\n.table > thead > tr.danger > th,\r\n.table > tbody > tr.danger > th,\r\n.table > tfoot > tr.danger > th {\r\n  background-color: #d9534f;\r\n}\r\n.table-hover > tbody > tr > td.danger:hover,\r\n.table-hover > tbody > tr > th.danger:hover,\r\n.table-hover > tbody > tr.danger:hover > td,\r\n.table-hover > tbody > tr:hover > .danger,\r\n.table-hover > tbody > tr.danger:hover > th {\r\n  background-color: #d43f3a;\r\n}\r\n.table-responsive {\r\n  overflow-x: auto;\r\n  min-height: 0.01%;\r\n}\r\n@media screen and (max-width: 767px) {\r\n  .table-responsive {\r\n    width: 100%;\r\n    margin-bottom: 15.75px;\r\n    overflow-y: hidden;\r\n    -ms-overflow-style: -ms-autohiding-scrollbar;\r\n    border: 1px solid #4e5d6c;\r\n  }\r\n  .table-responsive > .table {\r\n    margin-bottom: 0;\r\n  }\r\n  .table-responsive > .table > thead > tr > th,\r\n  .table-responsive > .table > tbody > tr > th,\r\n  .table-responsive > .table > tfoot > tr > th,\r\n  .table-responsive > .table > thead > tr > td,\r\n  .table-responsive > .table > tbody > tr > td,\r\n  .table-responsive > .table > tfoot > tr > td {\r\n    white-space: nowrap;\r\n  }\r\n  .table-responsive > .table-bordered {\r\n    border: 0;\r\n  }\r\n  .table-responsive > .table-bordered > thead > tr > th:first-child,\r\n  .table-responsive > .table-bordered > tbody > tr > th:first-child,\r\n  .table-responsive > .table-bordered > tfoot > tr > th:first-child,\r\n  .table-responsive > .table-bordered > thead > tr > td:first-child,\r\n  .table-responsive > .table-bordered > tbody > tr > td:first-child,\r\n  .table-responsive > .table-bordered > tfoot > tr > td:first-child {\r\n    border-left: 0;\r\n  }\r\n  .table-responsive > .table-bordered > thead > tr > th:last-child,\r\n  .table-responsive > .table-bordered > tbody > tr > th:last-child,\r\n  .table-responsive > .table-bordered > tfoot > tr > th:last-child,\r\n  .table-responsive > .table-bordered > thead > tr > td:last-child,\r\n  .table-responsive > .table-bordered > tbody > tr > td:last-child,\r\n  .table-responsive > .table-bordered > tfoot > tr > td:last-child {\r\n    border-right: 0;\r\n  }\r\n  .table-responsive > .table-bordered > tbody > tr:last-child > th,\r\n  .table-responsive > .table-bordered > tfoot > tr:last-child > th,\r\n  .table-responsive > .table-bordered > tbody > tr:last-child > td,\r\n  .table-responsive > .table-bordered > tfoot > tr:last-child > td {\r\n    border-bottom: 0;\r\n  }\r\n}\r\nfieldset {\r\n  padding: 0;\r\n  margin: 0;\r\n  border: 0;\r\n  min-width: 0;\r\n}\r\nlegend {\r\n  display: block;\r\n  width: 100%;\r\n  padding: 0;\r\n  margin-bottom: 21px;\r\n  font-size: 22.5px;\r\n  line-height: inherit;\r\n  color: #ebebeb;\r\n  border: 0;\r\n  border-bottom: 1px solid #4e5d6c;\r\n}\r\nlabel {\r\n  display: inline-block;\r\n  max-width: 100%;\r\n  margin-bottom: 5px;\r\n  font-weight: bold;\r\n}\r\ninput[type=\"search\"] {\r\n  -webkit-box-sizing: border-box;\r\n  -moz-box-sizing: border-box;\r\n  box-sizing: border-box;\r\n}\r\ninput[type=\"radio\"],\r\ninput[type=\"checkbox\"] {\r\n  margin: 4px 0 0;\r\n  margin-top: 1px \\9;\r\n  line-height: normal;\r\n}\r\ninput[type=\"file\"] {\r\n  display: block;\r\n}\r\ninput[type=\"range\"] {\r\n  display: block;\r\n  width: 100%;\r\n}\r\nselect[multiple],\r\nselect[size] {\r\n  height: auto;\r\n}\r\ninput[type=\"file\"]:focus,\r\ninput[type=\"radio\"]:focus,\r\ninput[type=\"checkbox\"]:focus {\r\n  outline: thin dotted;\r\n  outline: 5px auto -webkit-focus-ring-color;\r\n  outline-offset: -2px;\r\n}\r\noutput {\r\n  display: block;\r\n  padding-top: 9px;\r\n  font-size: 15px;\r\n  line-height: 1.42857143;\r\n  color: #2b3e50;\r\n}\r\n.form-control {\r\n  display: block;\r\n  width: 100%;\r\n  height: 39px;\r\n  padding: 8px 16px;\r\n  font-size: 15px;\r\n  line-height: 1.42857143;\r\n  color: #2b3e50;\r\n  background-color: #ffffff;\r\n  background-image: none;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\r\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\r\n  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\r\n  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\r\n  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\r\n}\r\n.form-control:focus {\r\n  border-color: transparent;\r\n  outline: 0;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 0, 0, 0.6);\r\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 0, 0, 0.6);\r\n}\r\n.form-control::-moz-placeholder {\r\n  color: #cccccc;\r\n  opacity: 1;\r\n}\r\n.form-control:-ms-input-placeholder {\r\n  color: #cccccc;\r\n}\r\n.form-control::-webkit-input-placeholder {\r\n  color: #cccccc;\r\n}\r\n.form-control[disabled],\r\n.form-control[readonly],\r\nfieldset[disabled] .form-control {\r\n  background-color: #ebebeb;\r\n  opacity: 1;\r\n}\r\n.form-control[disabled],\r\nfieldset[disabled] .form-control {\r\n  cursor: not-allowed;\r\n}\r\ntextarea.form-control {\r\n  height: auto;\r\n}\r\ninput[type=\"search\"] {\r\n  -webkit-appearance: none;\r\n}\r\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\r\n  input[type=\"date\"],\r\n  input[type=\"time\"],\r\n  input[type=\"datetime-local\"],\r\n  input[type=\"month\"] {\r\n    line-height: 39px;\r\n  }\r\n  input[type=\"date\"].input-sm,\r\n  input[type=\"time\"].input-sm,\r\n  input[type=\"datetime-local\"].input-sm,\r\n  input[type=\"month\"].input-sm,\r\n  .input-group-sm input[type=\"date\"],\r\n  .input-group-sm input[type=\"time\"],\r\n  .input-group-sm input[type=\"datetime-local\"],\r\n  .input-group-sm input[type=\"month\"] {\r\n    line-height: 31px;\r\n  }\r\n  input[type=\"date\"].input-lg,\r\n  input[type=\"time\"].input-lg,\r\n  input[type=\"datetime-local\"].input-lg,\r\n  input[type=\"month\"].input-lg,\r\n  .input-group-lg input[type=\"date\"],\r\n  .input-group-lg input[type=\"time\"],\r\n  .input-group-lg input[type=\"datetime-local\"],\r\n  .input-group-lg input[type=\"month\"] {\r\n    line-height: 52px;\r\n  }\r\n}\r\n.form-group {\r\n  margin-bottom: 15px;\r\n}\r\n.radio,\r\n.checkbox {\r\n  position: relative;\r\n  display: block;\r\n  margin-top: 10px;\r\n  margin-bottom: 10px;\r\n}\r\n.radio label,\r\n.checkbox label {\r\n  min-height: 21px;\r\n  padding-left: 20px;\r\n  margin-bottom: 0;\r\n  font-weight: normal;\r\n  cursor: pointer;\r\n}\r\n.radio input[type=\"radio\"],\r\n.radio-inline input[type=\"radio\"],\r\n.checkbox input[type=\"checkbox\"],\r\n.checkbox-inline input[type=\"checkbox\"] {\r\n  position: absolute;\r\n  margin-left: -20px;\r\n  margin-top: 4px \\9;\r\n}\r\n.radio + .radio,\r\n.checkbox + .checkbox {\r\n  margin-top: -5px;\r\n}\r\n.radio-inline,\r\n.checkbox-inline {\r\n  position: relative;\r\n  display: inline-block;\r\n  padding-left: 20px;\r\n  margin-bottom: 0;\r\n  vertical-align: middle;\r\n  font-weight: normal;\r\n  cursor: pointer;\r\n}\r\n.radio-inline + .radio-inline,\r\n.checkbox-inline + .checkbox-inline {\r\n  margin-top: 0;\r\n  margin-left: 10px;\r\n}\r\ninput[type=\"radio\"][disabled],\r\ninput[type=\"checkbox\"][disabled],\r\ninput[type=\"radio\"].disabled,\r\ninput[type=\"checkbox\"].disabled,\r\nfieldset[disabled] input[type=\"radio\"],\r\nfieldset[disabled] input[type=\"checkbox\"] {\r\n  cursor: not-allowed;\r\n}\r\n.radio-inline.disabled,\r\n.checkbox-inline.disabled,\r\nfieldset[disabled] .radio-inline,\r\nfieldset[disabled] .checkbox-inline {\r\n  cursor: not-allowed;\r\n}\r\n.radio.disabled label,\r\n.checkbox.disabled label,\r\nfieldset[disabled] .radio label,\r\nfieldset[disabled] .checkbox label {\r\n  cursor: not-allowed;\r\n}\r\n.form-control-static {\r\n  padding-top: 9px;\r\n  padding-bottom: 9px;\r\n  margin-bottom: 0;\r\n  min-height: 36px;\r\n}\r\n.form-control-static.input-lg,\r\n.form-control-static.input-sm {\r\n  padding-left: 0;\r\n  padding-right: 0;\r\n}\r\n.input-sm {\r\n  height: 31px;\r\n  padding: 5px 10px;\r\n  font-size: 13px;\r\n  line-height: 1.5;\r\n  border-radius: 0;\r\n}\r\nselect.input-sm {\r\n  height: 31px;\r\n  line-height: 31px;\r\n}\r\ntextarea.input-sm,\r\nselect[multiple].input-sm {\r\n  height: auto;\r\n}\r\n.form-group-sm .form-control {\r\n  height: 31px;\r\n  padding: 5px 10px;\r\n  font-size: 13px;\r\n  line-height: 1.5;\r\n  border-radius: 0;\r\n}\r\nselect.form-group-sm .form-control {\r\n  height: 31px;\r\n  line-height: 31px;\r\n}\r\ntextarea.form-group-sm .form-control,\r\nselect[multiple].form-group-sm .form-control {\r\n  height: auto;\r\n}\r\n.form-group-sm .form-control-static {\r\n  height: 31px;\r\n  padding: 5px 10px;\r\n  font-size: 13px;\r\n  line-height: 1.5;\r\n  min-height: 34px;\r\n}\r\n.input-lg {\r\n  height: 52px;\r\n  padding: 12px 24px;\r\n  font-size: 19px;\r\n  line-height: 1.3333333;\r\n  border-radius: 0;\r\n}\r\nselect.input-lg {\r\n  height: 52px;\r\n  line-height: 52px;\r\n}\r\ntextarea.input-lg,\r\nselect[multiple].input-lg {\r\n  height: auto;\r\n}\r\n.form-group-lg .form-control {\r\n  height: 52px;\r\n  padding: 12px 24px;\r\n  font-size: 19px;\r\n  line-height: 1.3333333;\r\n  border-radius: 0;\r\n}\r\nselect.form-group-lg .form-control {\r\n  height: 52px;\r\n  line-height: 52px;\r\n}\r\ntextarea.form-group-lg .form-control,\r\nselect[multiple].form-group-lg .form-control {\r\n  height: auto;\r\n}\r\n.form-group-lg .form-control-static {\r\n  height: 52px;\r\n  padding: 12px 24px;\r\n  font-size: 19px;\r\n  line-height: 1.3333333;\r\n  min-height: 40px;\r\n}\r\n.has-feedback {\r\n  position: relative;\r\n}\r\n.has-feedback .form-control {\r\n  padding-right: 48.75px;\r\n}\r\n.form-control-feedback {\r\n  position: absolute;\r\n  top: 0;\r\n  right: 0;\r\n  z-index: 2;\r\n  display: block;\r\n  width: 39px;\r\n  height: 39px;\r\n  line-height: 39px;\r\n  text-align: center;\r\n  pointer-events: none;\r\n}\r\n.input-lg + .form-control-feedback {\r\n  width: 52px;\r\n  height: 52px;\r\n  line-height: 52px;\r\n}\r\n.input-sm + .form-control-feedback {\r\n  width: 31px;\r\n  height: 31px;\r\n  line-height: 31px;\r\n}\r\n.has-success .help-block,\r\n.has-success .control-label,\r\n.has-success .radio,\r\n.has-success .checkbox,\r\n.has-success .radio-inline,\r\n.has-success .checkbox-inline,\r\n.has-success.radio label,\r\n.has-success.checkbox label,\r\n.has-success.radio-inline label,\r\n.has-success.checkbox-inline label {\r\n  color: #ebebeb;\r\n}\r\n.has-success .form-control {\r\n  border-color: #ebebeb;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\r\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\r\n}\r\n.has-success .form-control:focus {\r\n  border-color: #d2d2d2;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\r\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\r\n}\r\n.has-success .input-group-addon {\r\n  color: #ebebeb;\r\n  border-color: #ebebeb;\r\n  background-color: #5cb85c;\r\n}\r\n.has-success .form-control-feedback {\r\n  color: #ebebeb;\r\n}\r\n.has-warning .help-block,\r\n.has-warning .control-label,\r\n.has-warning .radio,\r\n.has-warning .checkbox,\r\n.has-warning .radio-inline,\r\n.has-warning .checkbox-inline,\r\n.has-warning.radio label,\r\n.has-warning.checkbox label,\r\n.has-warning.radio-inline label,\r\n.has-warning.checkbox-inline label {\r\n  color: #ebebeb;\r\n}\r\n.has-warning .form-control {\r\n  border-color: #ebebeb;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\r\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\r\n}\r\n.has-warning .form-control:focus {\r\n  border-color: #d2d2d2;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\r\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\r\n}\r\n.has-warning .input-group-addon {\r\n  color: #ebebeb;\r\n  border-color: #ebebeb;\r\n  background-color: #f0ad4e;\r\n}\r\n.has-warning .form-control-feedback {\r\n  color: #ebebeb;\r\n}\r\n.has-error .help-block,\r\n.has-error .control-label,\r\n.has-error .radio,\r\n.has-error .checkbox,\r\n.has-error .radio-inline,\r\n.has-error .checkbox-inline,\r\n.has-error.radio label,\r\n.has-error.checkbox label,\r\n.has-error.radio-inline label,\r\n.has-error.checkbox-inline label {\r\n  color: #ebebeb;\r\n}\r\n.has-error .form-control {\r\n  border-color: #ebebeb;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\r\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\r\n}\r\n.has-error .form-control:focus {\r\n  border-color: #d2d2d2;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\r\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff;\r\n}\r\n.has-error .input-group-addon {\r\n  color: #ebebeb;\r\n  border-color: #ebebeb;\r\n  background-color: #d9534f;\r\n}\r\n.has-error .form-control-feedback {\r\n  color: #ebebeb;\r\n}\r\n.has-feedback label ~ .form-control-feedback {\r\n  top: 26px;\r\n}\r\n.has-feedback label.sr-only ~ .form-control-feedback {\r\n  top: 0;\r\n}\r\n.help-block {\r\n  display: block;\r\n  margin-top: 5px;\r\n  margin-bottom: 10px;\r\n  color: #ffffff;\r\n}\r\n@media (min-width: 768px) {\r\n  .form-inline .form-group {\r\n    display: inline-block;\r\n    margin-bottom: 0;\r\n    vertical-align: middle;\r\n  }\r\n  .form-inline .form-control {\r\n    display: inline-block;\r\n    width: auto;\r\n    vertical-align: middle;\r\n  }\r\n  .form-inline .form-control-static {\r\n    display: inline-block;\r\n  }\r\n  .form-inline .input-group {\r\n    display: inline-table;\r\n    vertical-align: middle;\r\n  }\r\n  .form-inline .input-group .input-group-addon,\r\n  .form-inline .input-group .input-group-btn,\r\n  .form-inline .input-group .form-control {\r\n    width: auto;\r\n  }\r\n  .form-inline .input-group > .form-control {\r\n    width: 100%;\r\n  }\r\n  .form-inline .control-label {\r\n    margin-bottom: 0;\r\n    vertical-align: middle;\r\n  }\r\n  .form-inline .radio,\r\n  .form-inline .checkbox {\r\n    display: inline-block;\r\n    margin-top: 0;\r\n    margin-bottom: 0;\r\n    vertical-align: middle;\r\n  }\r\n  .form-inline .radio label,\r\n  .form-inline .checkbox label {\r\n    padding-left: 0;\r\n  }\r\n  .form-inline .radio input[type=\"radio\"],\r\n  .form-inline .checkbox input[type=\"checkbox\"] {\r\n    position: relative;\r\n    margin-left: 0;\r\n  }\r\n  .form-inline .has-feedback .form-control-feedback {\r\n    top: 0;\r\n  }\r\n}\r\n.form-horizontal .radio,\r\n.form-horizontal .checkbox,\r\n.form-horizontal .radio-inline,\r\n.form-horizontal .checkbox-inline {\r\n  margin-top: 0;\r\n  margin-bottom: 0;\r\n  padding-top: 9px;\r\n}\r\n.form-horizontal .radio,\r\n.form-horizontal .checkbox {\r\n  min-height: 30px;\r\n}\r\n.form-horizontal .form-group {\r\n  margin-left: -15px;\r\n  margin-right: -15px;\r\n}\r\n@media (min-width: 768px) {\r\n  .form-horizontal .control-label {\r\n    text-align: right;\r\n    margin-bottom: 0;\r\n    padding-top: 9px;\r\n  }\r\n}\r\n.form-horizontal .has-feedback .form-control-feedback {\r\n  right: 15px;\r\n}\r\n@media (min-width: 768px) {\r\n  .form-horizontal .form-group-lg .control-label {\r\n    padding-top: 16.9999996px;\r\n  }\r\n}\r\n@media (min-width: 768px) {\r\n  .form-horizontal .form-group-sm .control-label {\r\n    padding-top: 6px;\r\n  }\r\n}\r\n.btn {\r\n  display: inline-block;\r\n  margin-bottom: 0;\r\n  font-weight: normal;\r\n  text-align: center;\r\n  vertical-align: middle;\r\n  -ms-touch-action: manipulation;\r\n      touch-action: manipulation;\r\n  cursor: pointer;\r\n  background-image: none;\r\n  border: 1px solid transparent;\r\n  white-space: nowrap;\r\n  padding: 8px 16px;\r\n  font-size: 15px;\r\n  line-height: 1.42857143;\r\n  border-radius: 0;\r\n  -webkit-user-select: none;\r\n  -moz-user-select: none;\r\n  -ms-user-select: none;\r\n  user-select: none;\r\n}\r\n.btn:focus,\r\n.btn:active:focus,\r\n.btn.active:focus,\r\n.btn.focus,\r\n.btn:active.focus,\r\n.btn.active.focus {\r\n  outline: thin dotted;\r\n  outline: 5px auto -webkit-focus-ring-color;\r\n  outline-offset: -2px;\r\n}\r\n.btn:hover,\r\n.btn:focus,\r\n.btn.focus {\r\n  color: #ffffff;\r\n  text-decoration: none;\r\n}\r\n.btn:active,\r\n.btn.active {\r\n  outline: 0;\r\n  background-image: none;\r\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\r\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\r\n}\r\n.btn.disabled,\r\n.btn[disabled],\r\nfieldset[disabled] .btn {\r\n  cursor: not-allowed;\r\n  pointer-events: none;\r\n  opacity: 0.65;\r\n  filter: alpha(opacity=65);\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n}\r\n.btn-default {\r\n  color: #ffffff;\r\n  background-color: #4e5d6c;\r\n  border-color: transparent;\r\n}\r\n.btn-default:hover,\r\n.btn-default:focus,\r\n.btn-default.focus,\r\n.btn-default:active,\r\n.btn-default.active,\r\n.open > .dropdown-toggle.btn-default {\r\n  color: #ffffff;\r\n  background-color: #39444e;\r\n  border-color: rgba(0, 0, 0, 0);\r\n}\r\n.btn-default:active,\r\n.btn-default.active,\r\n.open > .dropdown-toggle.btn-default {\r\n  background-image: none;\r\n}\r\n.btn-default.disabled,\r\n.btn-default[disabled],\r\nfieldset[disabled] .btn-default,\r\n.btn-default.disabled:hover,\r\n.btn-default[disabled]:hover,\r\nfieldset[disabled] .btn-default:hover,\r\n.btn-default.disabled:focus,\r\n.btn-default[disabled]:focus,\r\nfieldset[disabled] .btn-default:focus,\r\n.btn-default.disabled.focus,\r\n.btn-default[disabled].focus,\r\nfieldset[disabled] .btn-default.focus,\r\n.btn-default.disabled:active,\r\n.btn-default[disabled]:active,\r\nfieldset[disabled] .btn-default:active,\r\n.btn-default.disabled.active,\r\n.btn-default[disabled].active,\r\nfieldset[disabled] .btn-default.active {\r\n  background-color: #4e5d6c;\r\n  border-color: transparent;\r\n}\r\n.btn-default .badge {\r\n  color: #4e5d6c;\r\n  background-color: #ffffff;\r\n}\r\n.btn-primary {\r\n  color: #ffffff;\r\n  background-color: #df691a;\r\n  border-color: transparent;\r\n}\r\n.btn-primary:hover,\r\n.btn-primary:focus,\r\n.btn-primary.focus,\r\n.btn-primary:active,\r\n.btn-primary.active,\r\n.open > .dropdown-toggle.btn-primary {\r\n  color: #ffffff;\r\n  background-color: #b15315;\r\n  border-color: rgba(0, 0, 0, 0);\r\n}\r\n.btn-primary:active,\r\n.btn-primary.active,\r\n.open > .dropdown-toggle.btn-primary {\r\n  background-image: none;\r\n}\r\n.btn-primary.disabled,\r\n.btn-primary[disabled],\r\nfieldset[disabled] .btn-primary,\r\n.btn-primary.disabled:hover,\r\n.btn-primary[disabled]:hover,\r\nfieldset[disabled] .btn-primary:hover,\r\n.btn-primary.disabled:focus,\r\n.btn-primary[disabled]:focus,\r\nfieldset[disabled] .btn-primary:focus,\r\n.btn-primary.disabled.focus,\r\n.btn-primary[disabled].focus,\r\nfieldset[disabled] .btn-primary.focus,\r\n.btn-primary.disabled:active,\r\n.btn-primary[disabled]:active,\r\nfieldset[disabled] .btn-primary:active,\r\n.btn-primary.disabled.active,\r\n.btn-primary[disabled].active,\r\nfieldset[disabled] .btn-primary.active {\r\n  background-color: #df691a;\r\n  border-color: transparent;\r\n}\r\n.btn-primary .badge {\r\n  color: #df691a;\r\n  background-color: #ffffff;\r\n}\r\n.btn-success {\r\n  color: #ffffff;\r\n  background-color: #5cb85c;\r\n  border-color: transparent;\r\n}\r\n.btn-success:hover,\r\n.btn-success:focus,\r\n.btn-success.focus,\r\n.btn-success:active,\r\n.btn-success.active,\r\n.open > .dropdown-toggle.btn-success {\r\n  color: #ffffff;\r\n  background-color: #449d44;\r\n  border-color: rgba(0, 0, 0, 0);\r\n}\r\n.btn-success:active,\r\n.btn-success.active,\r\n.open > .dropdown-toggle.btn-success {\r\n  background-image: none;\r\n}\r\n.btn-success.disabled,\r\n.btn-success[disabled],\r\nfieldset[disabled] .btn-success,\r\n.btn-success.disabled:hover,\r\n.btn-success[disabled]:hover,\r\nfieldset[disabled] .btn-success:hover,\r\n.btn-success.disabled:focus,\r\n.btn-success[disabled]:focus,\r\nfieldset[disabled] .btn-success:focus,\r\n.btn-success.disabled.focus,\r\n.btn-success[disabled].focus,\r\nfieldset[disabled] .btn-success.focus,\r\n.btn-success.disabled:active,\r\n.btn-success[disabled]:active,\r\nfieldset[disabled] .btn-success:active,\r\n.btn-success.disabled.active,\r\n.btn-success[disabled].active,\r\nfieldset[disabled] .btn-success.active {\r\n  background-color: #5cb85c;\r\n  border-color: transparent;\r\n}\r\n.btn-success .badge {\r\n  color: #5cb85c;\r\n  background-color: #ffffff;\r\n}\r\n.btn-info {\r\n  color: #ffffff;\r\n  background-color: #5bc0de;\r\n  border-color: transparent;\r\n}\r\n.btn-info:hover,\r\n.btn-info:focus,\r\n.btn-info.focus,\r\n.btn-info:active,\r\n.btn-info.active,\r\n.open > .dropdown-toggle.btn-info {\r\n  color: #ffffff;\r\n  background-color: #31b0d5;\r\n  border-color: rgba(0, 0, 0, 0);\r\n}\r\n.btn-info:active,\r\n.btn-info.active,\r\n.open > .dropdown-toggle.btn-info {\r\n  background-image: none;\r\n}\r\n.btn-info.disabled,\r\n.btn-info[disabled],\r\nfieldset[disabled] .btn-info,\r\n.btn-info.disabled:hover,\r\n.btn-info[disabled]:hover,\r\nfieldset[disabled] .btn-info:hover,\r\n.btn-info.disabled:focus,\r\n.btn-info[disabled]:focus,\r\nfieldset[disabled] .btn-info:focus,\r\n.btn-info.disabled.focus,\r\n.btn-info[disabled].focus,\r\nfieldset[disabled] .btn-info.focus,\r\n.btn-info.disabled:active,\r\n.btn-info[disabled]:active,\r\nfieldset[disabled] .btn-info:active,\r\n.btn-info.disabled.active,\r\n.btn-info[disabled].active,\r\nfieldset[disabled] .btn-info.active {\r\n  background-color: #5bc0de;\r\n  border-color: transparent;\r\n}\r\n.btn-info .badge {\r\n  color: #5bc0de;\r\n  background-color: #ffffff;\r\n}\r\n.btn-warning {\r\n  color: #ffffff;\r\n  background-color: #f0ad4e;\r\n  border-color: transparent;\r\n}\r\n.btn-warning:hover,\r\n.btn-warning:focus,\r\n.btn-warning.focus,\r\n.btn-warning:active,\r\n.btn-warning.active,\r\n.open > .dropdown-toggle.btn-warning {\r\n  color: #ffffff;\r\n  background-color: #ec971f;\r\n  border-color: rgba(0, 0, 0, 0);\r\n}\r\n.btn-warning:active,\r\n.btn-warning.active,\r\n.open > .dropdown-toggle.btn-warning {\r\n  background-image: none;\r\n}\r\n.btn-warning.disabled,\r\n.btn-warning[disabled],\r\nfieldset[disabled] .btn-warning,\r\n.btn-warning.disabled:hover,\r\n.btn-warning[disabled]:hover,\r\nfieldset[disabled] .btn-warning:hover,\r\n.btn-warning.disabled:focus,\r\n.btn-warning[disabled]:focus,\r\nfieldset[disabled] .btn-warning:focus,\r\n.btn-warning.disabled.focus,\r\n.btn-warning[disabled].focus,\r\nfieldset[disabled] .btn-warning.focus,\r\n.btn-warning.disabled:active,\r\n.btn-warning[disabled]:active,\r\nfieldset[disabled] .btn-warning:active,\r\n.btn-warning.disabled.active,\r\n.btn-warning[disabled].active,\r\nfieldset[disabled] .btn-warning.active {\r\n  background-color: #f0ad4e;\r\n  border-color: transparent;\r\n}\r\n.btn-warning .badge {\r\n  color: #f0ad4e;\r\n  background-color: #ffffff;\r\n}\r\n.btn-danger {\r\n  color: #ffffff;\r\n  background-color: #d9534f;\r\n  border-color: transparent;\r\n}\r\n.btn-danger:hover,\r\n.btn-danger:focus,\r\n.btn-danger.focus,\r\n.btn-danger:active,\r\n.btn-danger.active,\r\n.open > .dropdown-toggle.btn-danger {\r\n  color: #ffffff;\r\n  background-color: #c9302c;\r\n  border-color: rgba(0, 0, 0, 0);\r\n}\r\n.btn-danger:active,\r\n.btn-danger.active,\r\n.open > .dropdown-toggle.btn-danger {\r\n  background-image: none;\r\n}\r\n.btn-danger.disabled,\r\n.btn-danger[disabled],\r\nfieldset[disabled] .btn-danger,\r\n.btn-danger.disabled:hover,\r\n.btn-danger[disabled]:hover,\r\nfieldset[disabled] .btn-danger:hover,\r\n.btn-danger.disabled:focus,\r\n.btn-danger[disabled]:focus,\r\nfieldset[disabled] .btn-danger:focus,\r\n.btn-danger.disabled.focus,\r\n.btn-danger[disabled].focus,\r\nfieldset[disabled] .btn-danger.focus,\r\n.btn-danger.disabled:active,\r\n.btn-danger[disabled]:active,\r\nfieldset[disabled] .btn-danger:active,\r\n.btn-danger.disabled.active,\r\n.btn-danger[disabled].active,\r\nfieldset[disabled] .btn-danger.active {\r\n  background-color: #d9534f;\r\n  border-color: transparent;\r\n}\r\n.btn-danger .badge {\r\n  color: #d9534f;\r\n  background-color: #ffffff;\r\n}\r\n.btn-link {\r\n  color: #df691a;\r\n  font-weight: normal;\r\n  border-radius: 0;\r\n}\r\n.btn-link,\r\n.btn-link:active,\r\n.btn-link.active,\r\n.btn-link[disabled],\r\nfieldset[disabled] .btn-link {\r\n  background-color: transparent;\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n}\r\n.btn-link,\r\n.btn-link:hover,\r\n.btn-link:focus,\r\n.btn-link:active {\r\n  border-color: transparent;\r\n}\r\n.btn-link:hover,\r\n.btn-link:focus {\r\n  color: #df691a;\r\n  text-decoration: underline;\r\n  background-color: transparent;\r\n}\r\n.btn-link[disabled]:hover,\r\nfieldset[disabled] .btn-link:hover,\r\n.btn-link[disabled]:focus,\r\nfieldset[disabled] .btn-link:focus {\r\n  color: #4e5d6c;\r\n  text-decoration: none;\r\n}\r\n.btn-lg,\r\n.btn-group-lg > .btn {\r\n  padding: 12px 24px;\r\n  font-size: 19px;\r\n  line-height: 1.3333333;\r\n  border-radius: 0;\r\n}\r\n.btn-sm,\r\n.btn-group-sm > .btn {\r\n  padding: 5px 10px;\r\n  font-size: 13px;\r\n  line-height: 1.5;\r\n  border-radius: 0;\r\n}\r\n.btn-xs,\r\n.btn-group-xs > .btn {\r\n  padding: 1px 5px;\r\n  font-size: 13px;\r\n  line-height: 1.5;\r\n  border-radius: 0;\r\n}\r\n.btn-block {\r\n  display: block;\r\n  width: 100%;\r\n}\r\n.btn-block + .btn-block {\r\n  margin-top: 5px;\r\n}\r\ninput[type=\"submit\"].btn-block,\r\ninput[type=\"reset\"].btn-block,\r\ninput[type=\"button\"].btn-block {\r\n  width: 100%;\r\n}\r\n.fade {\r\n  opacity: 0;\r\n  -webkit-transition: opacity 0.15s linear;\r\n  -o-transition: opacity 0.15s linear;\r\n  transition: opacity 0.15s linear;\r\n}\r\n.fade.in {\r\n  opacity: 1;\r\n}\r\n.collapse {\r\n  display: none;\r\n}\r\n.collapse.in {\r\n  display: block;\r\n}\r\ntr.collapse.in {\r\n  display: table-row;\r\n}\r\ntbody.collapse.in {\r\n  display: table-row-group;\r\n}\r\n.collapsing {\r\n  position: relative;\r\n  height: 0;\r\n  overflow: hidden;\r\n  -webkit-transition-property: height, visibility;\r\n  -o-transition-property: height, visibility;\r\n     transition-property: height, visibility;\r\n  -webkit-transition-duration: 0.35s;\r\n  -o-transition-duration: 0.35s;\r\n     transition-duration: 0.35s;\r\n  -webkit-transition-timing-function: ease;\r\n  -o-transition-timing-function: ease;\r\n     transition-timing-function: ease;\r\n}\r\n.caret {\r\n  display: inline-block;\r\n  width: 0;\r\n  height: 0;\r\n  margin-left: 2px;\r\n  vertical-align: middle;\r\n  border-top: 4px dashed;\r\n  border-right: 4px solid transparent;\r\n  border-left: 4px solid transparent;\r\n}\r\n.dropup,\r\n.dropdown {\r\n  position: relative;\r\n}\r\n.dropdown-toggle:focus {\r\n  outline: 0;\r\n}\r\n.dropdown-menu {\r\n  position: absolute;\r\n  top: 100%;\r\n  left: 0;\r\n  z-index: 1000;\r\n  display: none;\r\n  float: left;\r\n  min-width: 160px;\r\n  padding: 5px 0;\r\n  margin: 2px 0 0;\r\n  list-style: none;\r\n  font-size: 15px;\r\n  text-align: left;\r\n  background-color: #4e5d6c;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\r\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\r\n  -webkit-background-clip: padding-box;\r\n          background-clip: padding-box;\r\n}\r\n.dropdown-menu.pull-right {\r\n  right: 0;\r\n  left: auto;\r\n}\r\n.dropdown-menu .divider {\r\n  height: 1px;\r\n  margin: 9.5px 0;\r\n  overflow: hidden;\r\n  background-color: #2b3e50;\r\n}\r\n.dropdown-menu > li > a {\r\n  display: block;\r\n  padding: 3px 20px;\r\n  clear: both;\r\n  font-weight: normal;\r\n  line-height: 1.42857143;\r\n  color: #ebebeb;\r\n  white-space: nowrap;\r\n}\r\n.dropdown-menu > li > a:hover,\r\n.dropdown-menu > li > a:focus {\r\n  text-decoration: none;\r\n  color: #ebebeb;\r\n  background-color: #485563;\r\n}\r\n.dropdown-menu > .active > a,\r\n.dropdown-menu > .active > a:hover,\r\n.dropdown-menu > .active > a:focus {\r\n  color: #ffffff;\r\n  text-decoration: none;\r\n  outline: 0;\r\n  background-color: #df691a;\r\n}\r\n.dropdown-menu > .disabled > a,\r\n.dropdown-menu > .disabled > a:hover,\r\n.dropdown-menu > .disabled > a:focus {\r\n  color: #2b3e50;\r\n}\r\n.dropdown-menu > .disabled > a:hover,\r\n.dropdown-menu > .disabled > a:focus {\r\n  text-decoration: none;\r\n  background-color: transparent;\r\n  background-image: none;\r\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\r\n  cursor: not-allowed;\r\n}\r\n.open > .dropdown-menu {\r\n  display: block;\r\n}\r\n.open > a {\r\n  outline: 0;\r\n}\r\n.dropdown-menu-right {\r\n  left: auto;\r\n  right: 0;\r\n}\r\n.dropdown-menu-left {\r\n  left: 0;\r\n  right: auto;\r\n}\r\n.dropdown-header {\r\n  display: block;\r\n  padding: 3px 20px;\r\n  font-size: 13px;\r\n  line-height: 1.42857143;\r\n  color: #2b3e50;\r\n  white-space: nowrap;\r\n}\r\n.dropdown-backdrop {\r\n  position: fixed;\r\n  left: 0;\r\n  right: 0;\r\n  bottom: 0;\r\n  top: 0;\r\n  z-index: 990;\r\n}\r\n.pull-right > .dropdown-menu {\r\n  right: 0;\r\n  left: auto;\r\n}\r\n.dropup .caret,\r\n.navbar-fixed-bottom .dropdown .caret {\r\n  border-top: 0;\r\n  border-bottom: 4px solid;\r\n  content: \"\";\r\n}\r\n.dropup .dropdown-menu,\r\n.navbar-fixed-bottom .dropdown .dropdown-menu {\r\n  top: auto;\r\n  bottom: 100%;\r\n  margin-bottom: 2px;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-right .dropdown-menu {\r\n    left: auto;\r\n    right: 0;\r\n  }\r\n  .navbar-right .dropdown-menu-left {\r\n    left: 0;\r\n    right: auto;\r\n  }\r\n}\r\n.btn-group,\r\n.btn-group-vertical {\r\n  position: relative;\r\n  display: inline-block;\r\n  vertical-align: middle;\r\n}\r\n.btn-group > .btn,\r\n.btn-group-vertical > .btn {\r\n  position: relative;\r\n  float: left;\r\n}\r\n.btn-group > .btn:hover,\r\n.btn-group-vertical > .btn:hover,\r\n.btn-group > .btn:focus,\r\n.btn-group-vertical > .btn:focus,\r\n.btn-group > .btn:active,\r\n.btn-group-vertical > .btn:active,\r\n.btn-group > .btn.active,\r\n.btn-group-vertical > .btn.active {\r\n  z-index: 2;\r\n}\r\n.btn-group .btn + .btn,\r\n.btn-group .btn + .btn-group,\r\n.btn-group .btn-group + .btn,\r\n.btn-group .btn-group + .btn-group {\r\n  margin-left: -1px;\r\n}\r\n.btn-toolbar {\r\n  margin-left: -5px;\r\n}\r\n.btn-toolbar .btn-group,\r\n.btn-toolbar .input-group {\r\n  float: left;\r\n}\r\n.btn-toolbar > .btn,\r\n.btn-toolbar > .btn-group,\r\n.btn-toolbar > .input-group {\r\n  margin-left: 5px;\r\n}\r\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\r\n  border-radius: 0;\r\n}\r\n.btn-group > .btn:first-child {\r\n  margin-left: 0;\r\n}\r\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\r\n  border-bottom-right-radius: 0;\r\n  border-top-right-radius: 0;\r\n}\r\n.btn-group > .btn:last-child:not(:first-child),\r\n.btn-group > .dropdown-toggle:not(:first-child) {\r\n  border-bottom-left-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.btn-group > .btn-group {\r\n  float: left;\r\n}\r\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\r\n  border-radius: 0;\r\n}\r\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\r\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\r\n  border-bottom-right-radius: 0;\r\n  border-top-right-radius: 0;\r\n}\r\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\r\n  border-bottom-left-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.btn-group .dropdown-toggle:active,\r\n.btn-group.open .dropdown-toggle {\r\n  outline: 0;\r\n}\r\n.btn-group > .btn + .dropdown-toggle {\r\n  padding-left: 8px;\r\n  padding-right: 8px;\r\n}\r\n.btn-group > .btn-lg + .dropdown-toggle {\r\n  padding-left: 12px;\r\n  padding-right: 12px;\r\n}\r\n.btn-group.open .dropdown-toggle {\r\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\r\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\r\n}\r\n.btn-group.open .dropdown-toggle.btn-link {\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n}\r\n.btn .caret {\r\n  margin-left: 0;\r\n}\r\n.btn-lg .caret {\r\n  border-width: 5px 5px 0;\r\n  border-bottom-width: 0;\r\n}\r\n.dropup .btn-lg .caret {\r\n  border-width: 0 5px 5px;\r\n}\r\n.btn-group-vertical > .btn,\r\n.btn-group-vertical > .btn-group,\r\n.btn-group-vertical > .btn-group > .btn {\r\n  display: block;\r\n  float: none;\r\n  width: 100%;\r\n  max-width: 100%;\r\n}\r\n.btn-group-vertical > .btn-group > .btn {\r\n  float: none;\r\n}\r\n.btn-group-vertical > .btn + .btn,\r\n.btn-group-vertical > .btn + .btn-group,\r\n.btn-group-vertical > .btn-group + .btn,\r\n.btn-group-vertical > .btn-group + .btn-group {\r\n  margin-top: -1px;\r\n  margin-left: 0;\r\n}\r\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\r\n  border-radius: 0;\r\n}\r\n.btn-group-vertical > .btn:first-child:not(:last-child) {\r\n  border-top-right-radius: 0;\r\n  border-bottom-right-radius: 0;\r\n  border-bottom-left-radius: 0;\r\n}\r\n.btn-group-vertical > .btn:last-child:not(:first-child) {\r\n  border-bottom-left-radius: 0;\r\n  border-top-right-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\r\n  border-radius: 0;\r\n}\r\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\r\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\r\n  border-bottom-right-radius: 0;\r\n  border-bottom-left-radius: 0;\r\n}\r\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\r\n  border-top-right-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.btn-group-justified {\r\n  display: table;\r\n  width: 100%;\r\n  table-layout: fixed;\r\n  border-collapse: separate;\r\n}\r\n.btn-group-justified > .btn,\r\n.btn-group-justified > .btn-group {\r\n  float: none;\r\n  display: table-cell;\r\n  width: 1%;\r\n}\r\n.btn-group-justified > .btn-group .btn {\r\n  width: 100%;\r\n}\r\n.btn-group-justified > .btn-group .dropdown-menu {\r\n  left: auto;\r\n}\r\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\r\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\r\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\r\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\r\n  position: absolute;\r\n  clip: rect(0, 0, 0, 0);\r\n  pointer-events: none;\r\n}\r\n.input-group {\r\n  position: relative;\r\n  display: table;\r\n  border-collapse: separate;\r\n}\r\n.input-group[class*=\"col-\"] {\r\n  float: none;\r\n  padding-left: 0;\r\n  padding-right: 0;\r\n}\r\n.input-group .form-control {\r\n  position: relative;\r\n  z-index: 2;\r\n  float: left;\r\n  width: 100%;\r\n  margin-bottom: 0;\r\n}\r\n.input-group-lg > .form-control,\r\n.input-group-lg > .input-group-addon,\r\n.input-group-lg > .input-group-btn > .btn {\r\n  height: 52px;\r\n  padding: 12px 24px;\r\n  font-size: 19px;\r\n  line-height: 1.3333333;\r\n  border-radius: 0;\r\n}\r\nselect.input-group-lg > .form-control,\r\nselect.input-group-lg > .input-group-addon,\r\nselect.input-group-lg > .input-group-btn > .btn {\r\n  height: 52px;\r\n  line-height: 52px;\r\n}\r\ntextarea.input-group-lg > .form-control,\r\ntextarea.input-group-lg > .input-group-addon,\r\ntextarea.input-group-lg > .input-group-btn > .btn,\r\nselect[multiple].input-group-lg > .form-control,\r\nselect[multiple].input-group-lg > .input-group-addon,\r\nselect[multiple].input-group-lg > .input-group-btn > .btn {\r\n  height: auto;\r\n}\r\n.input-group-sm > .form-control,\r\n.input-group-sm > .input-group-addon,\r\n.input-group-sm > .input-group-btn > .btn {\r\n  height: 31px;\r\n  padding: 5px 10px;\r\n  font-size: 13px;\r\n  line-height: 1.5;\r\n  border-radius: 0;\r\n}\r\nselect.input-group-sm > .form-control,\r\nselect.input-group-sm > .input-group-addon,\r\nselect.input-group-sm > .input-group-btn > .btn {\r\n  height: 31px;\r\n  line-height: 31px;\r\n}\r\ntextarea.input-group-sm > .form-control,\r\ntextarea.input-group-sm > .input-group-addon,\r\ntextarea.input-group-sm > .input-group-btn > .btn,\r\nselect[multiple].input-group-sm > .form-control,\r\nselect[multiple].input-group-sm > .input-group-addon,\r\nselect[multiple].input-group-sm > .input-group-btn > .btn {\r\n  height: auto;\r\n}\r\n.input-group-addon,\r\n.input-group-btn,\r\n.input-group .form-control {\r\n  display: table-cell;\r\n}\r\n.input-group-addon:not(:first-child):not(:last-child),\r\n.input-group-btn:not(:first-child):not(:last-child),\r\n.input-group .form-control:not(:first-child):not(:last-child) {\r\n  border-radius: 0;\r\n}\r\n.input-group-addon,\r\n.input-group-btn {\r\n  width: 1%;\r\n  white-space: nowrap;\r\n  vertical-align: middle;\r\n}\r\n.input-group-addon {\r\n  padding: 8px 16px;\r\n  font-size: 15px;\r\n  font-weight: normal;\r\n  line-height: 1;\r\n  color: #2b3e50;\r\n  text-align: center;\r\n  background-color: #4e5d6c;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n}\r\n.input-group-addon.input-sm {\r\n  padding: 5px 10px;\r\n  font-size: 13px;\r\n  border-radius: 0;\r\n}\r\n.input-group-addon.input-lg {\r\n  padding: 12px 24px;\r\n  font-size: 19px;\r\n  border-radius: 0;\r\n}\r\n.input-group-addon input[type=\"radio\"],\r\n.input-group-addon input[type=\"checkbox\"] {\r\n  margin-top: 0;\r\n}\r\n.input-group .form-control:first-child,\r\n.input-group-addon:first-child,\r\n.input-group-btn:first-child > .btn,\r\n.input-group-btn:first-child > .btn-group > .btn,\r\n.input-group-btn:first-child > .dropdown-toggle,\r\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\r\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\r\n  border-bottom-right-radius: 0;\r\n  border-top-right-radius: 0;\r\n}\r\n.input-group-addon:first-child {\r\n  border-right: 0;\r\n}\r\n.input-group .form-control:last-child,\r\n.input-group-addon:last-child,\r\n.input-group-btn:last-child > .btn,\r\n.input-group-btn:last-child > .btn-group > .btn,\r\n.input-group-btn:last-child > .dropdown-toggle,\r\n.input-group-btn:first-child > .btn:not(:first-child),\r\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\r\n  border-bottom-left-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.input-group-addon:last-child {\r\n  border-left: 0;\r\n}\r\n.input-group-btn {\r\n  position: relative;\r\n  font-size: 0;\r\n  white-space: nowrap;\r\n}\r\n.input-group-btn > .btn {\r\n  position: relative;\r\n}\r\n.input-group-btn > .btn + .btn {\r\n  margin-left: -1px;\r\n}\r\n.input-group-btn > .btn:hover,\r\n.input-group-btn > .btn:focus,\r\n.input-group-btn > .btn:active {\r\n  z-index: 2;\r\n}\r\n.input-group-btn:first-child > .btn,\r\n.input-group-btn:first-child > .btn-group {\r\n  margin-right: -1px;\r\n}\r\n.input-group-btn:last-child > .btn,\r\n.input-group-btn:last-child > .btn-group {\r\n  margin-left: -1px;\r\n}\r\n.nav {\r\n  margin-bottom: 0;\r\n  padding-left: 0;\r\n  list-style: none;\r\n}\r\n.nav > li {\r\n  position: relative;\r\n  display: block;\r\n}\r\n.nav > li > a {\r\n  position: relative;\r\n  display: block;\r\n  padding: 10px 15px;\r\n}\r\n.nav > li > a:hover,\r\n.nav > li > a:focus {\r\n  text-decoration: none;\r\n  background-color: #4e5d6c;\r\n}\r\n.nav > li.disabled > a {\r\n  color: #4e5d6c;\r\n}\r\n.nav > li.disabled > a:hover,\r\n.nav > li.disabled > a:focus {\r\n  color: #4e5d6c;\r\n  text-decoration: none;\r\n  background-color: transparent;\r\n  cursor: not-allowed;\r\n}\r\n.nav .open > a,\r\n.nav .open > a:hover,\r\n.nav .open > a:focus {\r\n  background-color: #4e5d6c;\r\n  border-color: #df691a;\r\n}\r\n.nav .nav-divider {\r\n  height: 1px;\r\n  margin: 9.5px 0;\r\n  overflow: hidden;\r\n  background-color: #e5e5e5;\r\n}\r\n.nav > li > a > img {\r\n  max-width: none;\r\n}\r\n.nav-tabs {\r\n  border-bottom: 1px solid transparent;\r\n}\r\n.nav-tabs > li {\r\n  float: left;\r\n  margin-bottom: -1px;\r\n}\r\n.nav-tabs > li > a {\r\n  margin-right: 2px;\r\n  line-height: 1.42857143;\r\n  border: 1px solid transparent;\r\n  border-radius: 0 0 0 0;\r\n}\r\n.nav-tabs > li > a:hover {\r\n  border-color: #4e5d6c #4e5d6c transparent;\r\n}\r\n.nav-tabs > li.active > a,\r\n.nav-tabs > li.active > a:hover,\r\n.nav-tabs > li.active > a:focus {\r\n  color: #ebebeb;\r\n  background-color: #2b3e50;\r\n  border: 1px solid #4e5d6c;\r\n  border-bottom-color: transparent;\r\n  cursor: default;\r\n}\r\n.nav-tabs.nav-justified {\r\n  width: 100%;\r\n  border-bottom: 0;\r\n}\r\n.nav-tabs.nav-justified > li {\r\n  float: none;\r\n}\r\n.nav-tabs.nav-justified > li > a {\r\n  text-align: center;\r\n  margin-bottom: 5px;\r\n}\r\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\r\n  top: auto;\r\n  left: auto;\r\n}\r\n@media (min-width: 768px) {\r\n  .nav-tabs.nav-justified > li {\r\n    display: table-cell;\r\n    width: 1%;\r\n  }\r\n  .nav-tabs.nav-justified > li > a {\r\n    margin-bottom: 0;\r\n  }\r\n}\r\n.nav-tabs.nav-justified > li > a {\r\n  margin-right: 0;\r\n  border-radius: 0;\r\n}\r\n.nav-tabs.nav-justified > .active > a,\r\n.nav-tabs.nav-justified > .active > a:hover,\r\n.nav-tabs.nav-justified > .active > a:focus {\r\n  border: 1px solid #4e5d6c;\r\n}\r\n@media (min-width: 768px) {\r\n  .nav-tabs.nav-justified > li > a {\r\n    border-bottom: 1px solid #4e5d6c;\r\n    border-radius: 0 0 0 0;\r\n  }\r\n  .nav-tabs.nav-justified > .active > a,\r\n  .nav-tabs.nav-justified > .active > a:hover,\r\n  .nav-tabs.nav-justified > .active > a:focus {\r\n    border-bottom-color: #4e5d6c;\r\n  }\r\n}\r\n.nav-pills > li {\r\n  float: left;\r\n}\r\n.nav-pills > li > a {\r\n  border-radius: 0;\r\n}\r\n.nav-pills > li + li {\r\n  margin-left: 2px;\r\n}\r\n.nav-pills > li.active > a,\r\n.nav-pills > li.active > a:hover,\r\n.nav-pills > li.active > a:focus {\r\n  color: #ffffff;\r\n  background-color: #df691a;\r\n}\r\n.nav-stacked > li {\r\n  float: none;\r\n}\r\n.nav-stacked > li + li {\r\n  margin-top: 2px;\r\n  margin-left: 0;\r\n}\r\n.nav-justified {\r\n  width: 100%;\r\n}\r\n.nav-justified > li {\r\n  float: none;\r\n}\r\n.nav-justified > li > a {\r\n  text-align: center;\r\n  margin-bottom: 5px;\r\n}\r\n.nav-justified > .dropdown .dropdown-menu {\r\n  top: auto;\r\n  left: auto;\r\n}\r\n@media (min-width: 768px) {\r\n  .nav-justified > li {\r\n    display: table-cell;\r\n    width: 1%;\r\n  }\r\n  .nav-justified > li > a {\r\n    margin-bottom: 0;\r\n  }\r\n}\r\n.nav-tabs-justified {\r\n  border-bottom: 0;\r\n}\r\n.nav-tabs-justified > li > a {\r\n  margin-right: 0;\r\n  border-radius: 0;\r\n}\r\n.nav-tabs-justified > .active > a,\r\n.nav-tabs-justified > .active > a:hover,\r\n.nav-tabs-justified > .active > a:focus {\r\n  border: 1px solid #4e5d6c;\r\n}\r\n@media (min-width: 768px) {\r\n  .nav-tabs-justified > li > a {\r\n    border-bottom: 1px solid #4e5d6c;\r\n    border-radius: 0 0 0 0;\r\n  }\r\n  .nav-tabs-justified > .active > a,\r\n  .nav-tabs-justified > .active > a:hover,\r\n  .nav-tabs-justified > .active > a:focus {\r\n    border-bottom-color: #4e5d6c;\r\n  }\r\n}\r\n.tab-content > .tab-pane {\r\n  display: none;\r\n}\r\n.tab-content > .active {\r\n  display: block;\r\n}\r\n.nav-tabs .dropdown-menu {\r\n  margin-top: -1px;\r\n  border-top-right-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.navbar {\r\n  position: relative;\r\n  min-height: 40px;\r\n  margin-bottom: 21px;\r\n  border: 1px solid transparent;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar {\r\n    border-radius: 0;\r\n  }\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-header {\r\n    float: left;\r\n  }\r\n}\r\n.navbar-collapse {\r\n  overflow-x: visible;\r\n  padding-right: 15px;\r\n  padding-left: 15px;\r\n  border-top: 1px solid transparent;\r\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\r\n          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\r\n  -webkit-overflow-scrolling: touch;\r\n}\r\n.navbar-collapse.in {\r\n  overflow-y: auto;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-collapse {\r\n    width: auto;\r\n    border-top: 0;\r\n    -webkit-box-shadow: none;\r\n            box-shadow: none;\r\n  }\r\n  .navbar-collapse.collapse {\r\n    display: block !important;\r\n    height: auto !important;\r\n    padding-bottom: 0;\r\n    overflow: visible !important;\r\n  }\r\n  .navbar-collapse.in {\r\n    overflow-y: visible;\r\n  }\r\n  .navbar-fixed-top .navbar-collapse,\r\n  .navbar-static-top .navbar-collapse,\r\n  .navbar-fixed-bottom .navbar-collapse {\r\n    padding-left: 0;\r\n    padding-right: 0;\r\n  }\r\n}\r\n.navbar-fixed-top .navbar-collapse,\r\n.navbar-fixed-bottom .navbar-collapse {\r\n  max-height: 340px;\r\n}\r\n@media (max-device-width: 480px) and (orientation: landscape) {\r\n  .navbar-fixed-top .navbar-collapse,\r\n  .navbar-fixed-bottom .navbar-collapse {\r\n    max-height: 200px;\r\n  }\r\n}\r\n.container > .navbar-header,\r\n.container-fluid > .navbar-header,\r\n.container > .navbar-collapse,\r\n.container-fluid > .navbar-collapse {\r\n  margin-right: -15px;\r\n  margin-left: -15px;\r\n}\r\n@media (min-width: 768px) {\r\n  .container > .navbar-header,\r\n  .container-fluid > .navbar-header,\r\n  .container > .navbar-collapse,\r\n  .container-fluid > .navbar-collapse {\r\n    margin-right: 0;\r\n    margin-left: 0;\r\n  }\r\n}\r\n.navbar-static-top {\r\n  z-index: 1000;\r\n  border-width: 0 0 1px;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-static-top {\r\n    border-radius: 0;\r\n  }\r\n}\r\n.navbar-fixed-top,\r\n.navbar-fixed-bottom {\r\n  position: fixed;\r\n  right: 0;\r\n  left: 0;\r\n  z-index: 1030;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-fixed-top,\r\n  .navbar-fixed-bottom {\r\n    border-radius: 0;\r\n  }\r\n}\r\n.navbar-fixed-top {\r\n  top: 0;\r\n  border-width: 0 0 1px;\r\n}\r\n.navbar-fixed-bottom {\r\n  bottom: 0;\r\n  margin-bottom: 0;\r\n  border-width: 1px 0 0;\r\n}\r\n.navbar-brand {\r\n  float: left;\r\n  padding: 9.5px 15px;\r\n  font-size: 19px;\r\n  line-height: 21px;\r\n  height: 40px;\r\n}\r\n.navbar-brand:hover,\r\n.navbar-brand:focus {\r\n  text-decoration: none;\r\n}\r\n.navbar-brand > img {\r\n  display: block;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar > .container .navbar-brand,\r\n  .navbar > .container-fluid .navbar-brand {\r\n    margin-left: -15px;\r\n  }\r\n}\r\n.navbar-toggle {\r\n  position: relative;\r\n  float: right;\r\n  margin-right: 15px;\r\n  padding: 9px 10px;\r\n  margin-top: 3px;\r\n  margin-bottom: 3px;\r\n  background-color: transparent;\r\n  background-image: none;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n}\r\n.navbar-toggle:focus {\r\n  outline: 0;\r\n}\r\n.navbar-toggle .icon-bar {\r\n  display: block;\r\n  width: 22px;\r\n  height: 2px;\r\n  border-radius: 1px;\r\n}\r\n.navbar-toggle .icon-bar + .icon-bar {\r\n  margin-top: 4px;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-toggle {\r\n    display: none;\r\n  }\r\n}\r\n.navbar-nav {\r\n  margin: 4.75px -15px;\r\n}\r\n.navbar-nav > li > a {\r\n  padding-top: 10px;\r\n  padding-bottom: 10px;\r\n  line-height: 21px;\r\n}\r\n@media (max-width: 767px) {\r\n  .navbar-nav .open .dropdown-menu {\r\n    position: static;\r\n    float: none;\r\n    width: auto;\r\n    margin-top: 0;\r\n    background-color: transparent;\r\n    border: 0;\r\n    -webkit-box-shadow: none;\r\n            box-shadow: none;\r\n  }\r\n  .navbar-nav .open .dropdown-menu > li > a,\r\n  .navbar-nav .open .dropdown-menu .dropdown-header {\r\n    padding: 5px 15px 5px 25px;\r\n  }\r\n  .navbar-nav .open .dropdown-menu > li > a {\r\n    line-height: 21px;\r\n  }\r\n  .navbar-nav .open .dropdown-menu > li > a:hover,\r\n  .navbar-nav .open .dropdown-menu > li > a:focus {\r\n    background-image: none;\r\n  }\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-nav {\r\n    float: left;\r\n    margin: 0;\r\n  }\r\n  .navbar-nav > li {\r\n    float: left;\r\n  }\r\n  .navbar-nav > li > a {\r\n    padding-top: 9.5px;\r\n    padding-bottom: 9.5px;\r\n  }\r\n}\r\n.navbar-form {\r\n  margin-left: -15px;\r\n  margin-right: -15px;\r\n  padding: 10px 15px;\r\n  border-top: 1px solid transparent;\r\n  border-bottom: 1px solid transparent;\r\n  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\r\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\r\n  margin-top: 0.5px;\r\n  margin-bottom: 0.5px;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-form .form-group {\r\n    display: inline-block;\r\n    margin-bottom: 0;\r\n    vertical-align: middle;\r\n  }\r\n  .navbar-form .form-control {\r\n    display: inline-block;\r\n    width: auto;\r\n    vertical-align: middle;\r\n  }\r\n  .navbar-form .form-control-static {\r\n    display: inline-block;\r\n  }\r\n  .navbar-form .input-group {\r\n    display: inline-table;\r\n    vertical-align: middle;\r\n  }\r\n  .navbar-form .input-group .input-group-addon,\r\n  .navbar-form .input-group .input-group-btn,\r\n  .navbar-form .input-group .form-control {\r\n    width: auto;\r\n  }\r\n  .navbar-form .input-group > .form-control {\r\n    width: 100%;\r\n  }\r\n  .navbar-form .control-label {\r\n    margin-bottom: 0;\r\n    vertical-align: middle;\r\n  }\r\n  .navbar-form .radio,\r\n  .navbar-form .checkbox {\r\n    display: inline-block;\r\n    margin-top: 0;\r\n    margin-bottom: 0;\r\n    vertical-align: middle;\r\n  }\r\n  .navbar-form .radio label,\r\n  .navbar-form .checkbox label {\r\n    padding-left: 0;\r\n  }\r\n  .navbar-form .radio input[type=\"radio\"],\r\n  .navbar-form .checkbox input[type=\"checkbox\"] {\r\n    position: relative;\r\n    margin-left: 0;\r\n  }\r\n  .navbar-form .has-feedback .form-control-feedback {\r\n    top: 0;\r\n  }\r\n}\r\n@media (max-width: 767px) {\r\n  .navbar-form .form-group {\r\n    margin-bottom: 5px;\r\n  }\r\n  .navbar-form .form-group:last-child {\r\n    margin-bottom: 0;\r\n  }\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-form {\r\n    width: auto;\r\n    border: 0;\r\n    margin-left: 0;\r\n    margin-right: 0;\r\n    padding-top: 0;\r\n    padding-bottom: 0;\r\n    -webkit-box-shadow: none;\r\n    box-shadow: none;\r\n  }\r\n}\r\n.navbar-nav > li > .dropdown-menu {\r\n  margin-top: 0;\r\n  border-top-right-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\r\n  margin-bottom: 0;\r\n  border-top-right-radius: 0;\r\n  border-top-left-radius: 0;\r\n  border-bottom-right-radius: 0;\r\n  border-bottom-left-radius: 0;\r\n}\r\n.navbar-btn {\r\n  margin-top: 0.5px;\r\n  margin-bottom: 0.5px;\r\n}\r\n.navbar-btn.btn-sm {\r\n  margin-top: 4.5px;\r\n  margin-bottom: 4.5px;\r\n}\r\n.navbar-btn.btn-xs {\r\n  margin-top: 9px;\r\n  margin-bottom: 9px;\r\n}\r\n.navbar-text {\r\n  margin-top: 9.5px;\r\n  margin-bottom: 9.5px;\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-text {\r\n    float: left;\r\n    margin-left: 15px;\r\n    margin-right: 15px;\r\n  }\r\n}\r\n@media (min-width: 768px) {\r\n  .navbar-left {\r\n    float: left !important;\r\n  }\r\n  .navbar-right {\r\n    float: right !important;\r\n    margin-right: -15px;\r\n  }\r\n  .navbar-right ~ .navbar-right {\r\n    margin-right: 0;\r\n  }\r\n}\r\n.navbar-default {\r\n  background-color: #4e5d6c;\r\n  border-color: transparent;\r\n}\r\n.navbar-default .navbar-brand {\r\n  color: #ebebeb;\r\n}\r\n.navbar-default .navbar-brand:hover,\r\n.navbar-default .navbar-brand:focus {\r\n  color: #ebebeb;\r\n  background-color: transparent;\r\n}\r\n.navbar-default .navbar-text {\r\n  color: #ebebeb;\r\n}\r\n.navbar-default .navbar-nav > li > a {\r\n  color: #ebebeb;\r\n}\r\n.navbar-default .navbar-nav > li > a:hover,\r\n.navbar-default .navbar-nav > li > a:focus {\r\n  color: #ebebeb;\r\n  background-color: #485563;\r\n}\r\n.navbar-default .navbar-nav > .active > a,\r\n.navbar-default .navbar-nav > .active > a:hover,\r\n.navbar-default .navbar-nav > .active > a:focus {\r\n  color: #ebebeb;\r\n  background-color: #485563;\r\n}\r\n.navbar-default .navbar-nav > .disabled > a,\r\n.navbar-default .navbar-nav > .disabled > a:hover,\r\n.navbar-default .navbar-nav > .disabled > a:focus {\r\n  color: #cccccc;\r\n  background-color: transparent;\r\n}\r\n.navbar-default .navbar-toggle {\r\n  border-color: transparent;\r\n}\r\n.navbar-default .navbar-toggle:hover,\r\n.navbar-default .navbar-toggle:focus {\r\n  background-color: #485563;\r\n}\r\n.navbar-default .navbar-toggle .icon-bar {\r\n  background-color: #ebebeb;\r\n}\r\n.navbar-default .navbar-collapse,\r\n.navbar-default .navbar-form {\r\n  border-color: transparent;\r\n}\r\n.navbar-default .navbar-nav > .open > a,\r\n.navbar-default .navbar-nav > .open > a:hover,\r\n.navbar-default .navbar-nav > .open > a:focus {\r\n  background-color: #485563;\r\n  color: #ebebeb;\r\n}\r\n@media (max-width: 767px) {\r\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\r\n    color: #ebebeb;\r\n  }\r\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\r\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\r\n    color: #ebebeb;\r\n    background-color: #485563;\r\n  }\r\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\r\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\r\n  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\r\n    color: #ebebeb;\r\n    background-color: #485563;\r\n  }\r\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\r\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\r\n  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\r\n    color: #cccccc;\r\n    background-color: transparent;\r\n  }\r\n}\r\n.navbar-default .navbar-link {\r\n  color: #ebebeb;\r\n}\r\n.navbar-default .navbar-link:hover {\r\n  color: #ebebeb;\r\n}\r\n.navbar-default .btn-link {\r\n  color: #ebebeb;\r\n}\r\n.navbar-default .btn-link:hover,\r\n.navbar-default .btn-link:focus {\r\n  color: #ebebeb;\r\n}\r\n.navbar-default .btn-link[disabled]:hover,\r\nfieldset[disabled] .navbar-default .btn-link:hover,\r\n.navbar-default .btn-link[disabled]:focus,\r\nfieldset[disabled] .navbar-default .btn-link:focus {\r\n  color: #cccccc;\r\n}\r\n.navbar-inverse {\r\n  background-color: #df691a;\r\n  border-color: transparent;\r\n}\r\n.navbar-inverse .navbar-brand {\r\n  color: #ebebeb;\r\n}\r\n.navbar-inverse .navbar-brand:hover,\r\n.navbar-inverse .navbar-brand:focus {\r\n  color: #ebebeb;\r\n  background-color: transparent;\r\n}\r\n.navbar-inverse .navbar-text {\r\n  color: #ebebeb;\r\n}\r\n.navbar-inverse .navbar-nav > li > a {\r\n  color: #ebebeb;\r\n}\r\n.navbar-inverse .navbar-nav > li > a:hover,\r\n.navbar-inverse .navbar-nav > li > a:focus {\r\n  color: #ebebeb;\r\n  background-color: #c85e17;\r\n}\r\n.navbar-inverse .navbar-nav > .active > a,\r\n.navbar-inverse .navbar-nav > .active > a:hover,\r\n.navbar-inverse .navbar-nav > .active > a:focus {\r\n  color: #ebebeb;\r\n  background-color: #c85e17;\r\n}\r\n.navbar-inverse .navbar-nav > .disabled > a,\r\n.navbar-inverse .navbar-nav > .disabled > a:hover,\r\n.navbar-inverse .navbar-nav > .disabled > a:focus {\r\n  color: #444444;\r\n  background-color: transparent;\r\n}\r\n.navbar-inverse .navbar-toggle {\r\n  border-color: transparent;\r\n}\r\n.navbar-inverse .navbar-toggle:hover,\r\n.navbar-inverse .navbar-toggle:focus {\r\n  background-color: #c85e17;\r\n}\r\n.navbar-inverse .navbar-toggle .icon-bar {\r\n  background-color: #ebebeb;\r\n}\r\n.navbar-inverse .navbar-collapse,\r\n.navbar-inverse .navbar-form {\r\n  border-color: #bf5a16;\r\n}\r\n.navbar-inverse .navbar-nav > .open > a,\r\n.navbar-inverse .navbar-nav > .open > a:hover,\r\n.navbar-inverse .navbar-nav > .open > a:focus {\r\n  background-color: #c85e17;\r\n  color: #ebebeb;\r\n}\r\n@media (max-width: 767px) {\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\r\n    border-color: transparent;\r\n  }\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\r\n    background-color: transparent;\r\n  }\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\r\n    color: #ebebeb;\r\n  }\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\r\n    color: #ebebeb;\r\n    background-color: #c85e17;\r\n  }\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\r\n    color: #ebebeb;\r\n    background-color: #c85e17;\r\n  }\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\r\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\r\n    color: #444444;\r\n    background-color: transparent;\r\n  }\r\n}\r\n.navbar-inverse .navbar-link {\r\n  color: #ebebeb;\r\n}\r\n.navbar-inverse .navbar-link:hover {\r\n  color: #ebebeb;\r\n}\r\n.navbar-inverse .btn-link {\r\n  color: #ebebeb;\r\n}\r\n.navbar-inverse .btn-link:hover,\r\n.navbar-inverse .btn-link:focus {\r\n  color: #ebebeb;\r\n}\r\n.navbar-inverse .btn-link[disabled]:hover,\r\nfieldset[disabled] .navbar-inverse .btn-link:hover,\r\n.navbar-inverse .btn-link[disabled]:focus,\r\nfieldset[disabled] .navbar-inverse .btn-link:focus {\r\n  color: #444444;\r\n}\r\n.breadcrumb {\r\n  padding: 8px 15px;\r\n  margin-bottom: 21px;\r\n  list-style: none;\r\n  background-color: #4e5d6c;\r\n  border-radius: 0;\r\n}\r\n.breadcrumb > li {\r\n  display: inline-block;\r\n}\r\n.breadcrumb > li + li:before {\r\n  content: \"/\\00a0\";\r\n  padding: 0 5px;\r\n  color: #ebebeb;\r\n}\r\n.breadcrumb > .active {\r\n  color: #ebebeb;\r\n}\r\n.pagination {\r\n  display: inline-block;\r\n  padding-left: 0;\r\n  margin: 21px 0;\r\n  border-radius: 0;\r\n}\r\n.pagination > li {\r\n  display: inline;\r\n}\r\n.pagination > li > a,\r\n.pagination > li > span {\r\n  position: relative;\r\n  float: left;\r\n  padding: 8px 16px;\r\n  line-height: 1.42857143;\r\n  text-decoration: none;\r\n  color: #ebebeb;\r\n  background-color: #4e5d6c;\r\n  border: 1px solid transparent;\r\n  margin-left: -1px;\r\n}\r\n.pagination > li:first-child > a,\r\n.pagination > li:first-child > span {\r\n  margin-left: 0;\r\n  border-bottom-left-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.pagination > li:last-child > a,\r\n.pagination > li:last-child > span {\r\n  border-bottom-right-radius: 0;\r\n  border-top-right-radius: 0;\r\n}\r\n.pagination > li > a:hover,\r\n.pagination > li > span:hover,\r\n.pagination > li > a:focus,\r\n.pagination > li > span:focus {\r\n  color: #ebebeb;\r\n  background-color: #485563;\r\n  border-color: transparent;\r\n}\r\n.pagination > .active > a,\r\n.pagination > .active > span,\r\n.pagination > .active > a:hover,\r\n.pagination > .active > span:hover,\r\n.pagination > .active > a:focus,\r\n.pagination > .active > span:focus {\r\n  z-index: 2;\r\n  color: #ebebeb;\r\n  background-color: #df691a;\r\n  border-color: transparent;\r\n  cursor: default;\r\n}\r\n.pagination > .disabled > span,\r\n.pagination > .disabled > span:hover,\r\n.pagination > .disabled > span:focus,\r\n.pagination > .disabled > a,\r\n.pagination > .disabled > a:hover,\r\n.pagination > .disabled > a:focus {\r\n  color: #323c46;\r\n  background-color: #4e5d6c;\r\n  border-color: transparent;\r\n  cursor: not-allowed;\r\n}\r\n.pagination-lg > li > a,\r\n.pagination-lg > li > span {\r\n  padding: 12px 24px;\r\n  font-size: 19px;\r\n}\r\n.pagination-lg > li:first-child > a,\r\n.pagination-lg > li:first-child > span {\r\n  border-bottom-left-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.pagination-lg > li:last-child > a,\r\n.pagination-lg > li:last-child > span {\r\n  border-bottom-right-radius: 0;\r\n  border-top-right-radius: 0;\r\n}\r\n.pagination-sm > li > a,\r\n.pagination-sm > li > span {\r\n  padding: 5px 10px;\r\n  font-size: 13px;\r\n}\r\n.pagination-sm > li:first-child > a,\r\n.pagination-sm > li:first-child > span {\r\n  border-bottom-left-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.pagination-sm > li:last-child > a,\r\n.pagination-sm > li:last-child > span {\r\n  border-bottom-right-radius: 0;\r\n  border-top-right-radius: 0;\r\n}\r\n.pager {\r\n  padding-left: 0;\r\n  margin: 21px 0;\r\n  list-style: none;\r\n  text-align: center;\r\n}\r\n.pager li {\r\n  display: inline;\r\n}\r\n.pager li > a,\r\n.pager li > span {\r\n  display: inline-block;\r\n  padding: 5px 14px;\r\n  background-color: #4e5d6c;\r\n  border: 1px solid transparent;\r\n  border-radius: 15px;\r\n}\r\n.pager li > a:hover,\r\n.pager li > a:focus {\r\n  text-decoration: none;\r\n  background-color: #485563;\r\n}\r\n.pager .next > a,\r\n.pager .next > span {\r\n  float: right;\r\n}\r\n.pager .previous > a,\r\n.pager .previous > span {\r\n  float: left;\r\n}\r\n.pager .disabled > a,\r\n.pager .disabled > a:hover,\r\n.pager .disabled > a:focus,\r\n.pager .disabled > span {\r\n  color: #323c46;\r\n  background-color: #4e5d6c;\r\n  cursor: not-allowed;\r\n}\r\n.label {\r\n  display: inline;\r\n  padding: .2em .6em .3em;\r\n  font-size: 75%;\r\n  font-weight: bold;\r\n  line-height: 1;\r\n  color: #ffffff;\r\n  text-align: center;\r\n  white-space: nowrap;\r\n  vertical-align: baseline;\r\n  border-radius: .25em;\r\n}\r\na.label:hover,\r\na.label:focus {\r\n  color: #ffffff;\r\n  text-decoration: none;\r\n  cursor: pointer;\r\n}\r\n.label:empty {\r\n  display: none;\r\n}\r\n.btn .label {\r\n  position: relative;\r\n  top: -1px;\r\n}\r\n.label-default {\r\n  background-color: #4e5d6c;\r\n}\r\n.label-default[href]:hover,\r\n.label-default[href]:focus {\r\n  background-color: #39444e;\r\n}\r\n.label-primary {\r\n  background-color: #df691a;\r\n}\r\n.label-primary[href]:hover,\r\n.label-primary[href]:focus {\r\n  background-color: #b15315;\r\n}\r\n.label-success {\r\n  background-color: #5cb85c;\r\n}\r\n.label-success[href]:hover,\r\n.label-success[href]:focus {\r\n  background-color: #449d44;\r\n}\r\n.label-info {\r\n  background-color: #5bc0de;\r\n}\r\n.label-info[href]:hover,\r\n.label-info[href]:focus {\r\n  background-color: #31b0d5;\r\n}\r\n.label-warning {\r\n  background-color: #f0ad4e;\r\n}\r\n.label-warning[href]:hover,\r\n.label-warning[href]:focus {\r\n  background-color: #ec971f;\r\n}\r\n.label-danger {\r\n  background-color: #d9534f;\r\n}\r\n.label-danger[href]:hover,\r\n.label-danger[href]:focus {\r\n  background-color: #c9302c;\r\n}\r\n.badge {\r\n  display: inline-block;\r\n  min-width: 10px;\r\n  padding: 3px 7px;\r\n  font-size: 13px;\r\n  font-weight: 300;\r\n  color: #ebebeb;\r\n  line-height: 1;\r\n  vertical-align: baseline;\r\n  white-space: nowrap;\r\n  text-align: center;\r\n  background-color: #4e5d6c;\r\n  border-radius: 10px;\r\n}\r\n.badge:empty {\r\n  display: none;\r\n}\r\n.btn .badge {\r\n  position: relative;\r\n  top: -1px;\r\n}\r\n.btn-xs .badge,\r\n.btn-group-xs > .btn .badge {\r\n  top: 0;\r\n  padding: 1px 5px;\r\n}\r\na.badge:hover,\r\na.badge:focus {\r\n  color: #ffffff;\r\n  text-decoration: none;\r\n  cursor: pointer;\r\n}\r\n.list-group-item.active > .badge,\r\n.nav-pills > .active > a > .badge {\r\n  color: #df691a;\r\n  background-color: #ffffff;\r\n}\r\n.list-group-item > .badge {\r\n  float: right;\r\n}\r\n.list-group-item > .badge + .badge {\r\n  margin-right: 5px;\r\n}\r\n.nav-pills > li > a > .badge {\r\n  margin-left: 3px;\r\n}\r\n.jumbotron {\r\n  padding: 30px 15px;\r\n  margin-bottom: 30px;\r\n  color: inherit;\r\n  background-color: #4e5d6c;\r\n}\r\n.jumbotron h1,\r\n.jumbotron .h1 {\r\n  color: inherit;\r\n}\r\n.jumbotron p {\r\n  margin-bottom: 15px;\r\n  font-size: 23px;\r\n  font-weight: 200;\r\n}\r\n.jumbotron > hr {\r\n  border-top-color: #39444e;\r\n}\r\n.container .jumbotron,\r\n.container-fluid .jumbotron {\r\n  border-radius: 0;\r\n}\r\n.jumbotron .container {\r\n  max-width: 100%;\r\n}\r\n@media screen and (min-width: 768px) {\r\n  .jumbotron {\r\n    padding: 48px 0;\r\n  }\r\n  .container .jumbotron,\r\n  .container-fluid .jumbotron {\r\n    padding-left: 60px;\r\n    padding-right: 60px;\r\n  }\r\n  .jumbotron h1,\r\n  .jumbotron .h1 {\r\n    font-size: 67.5px;\r\n  }\r\n}\r\n.thumbnail {\r\n  display: block;\r\n  padding: 4px;\r\n  margin-bottom: 21px;\r\n  line-height: 1.42857143;\r\n  background-color: #2b3e50;\r\n  border: 1px solid #dddddd;\r\n  border-radius: 0;\r\n  -webkit-transition: border 0.2s ease-in-out;\r\n  -o-transition: border 0.2s ease-in-out;\r\n  transition: border 0.2s ease-in-out;\r\n}\r\n.thumbnail > img,\r\n.thumbnail a > img {\r\n  margin-left: auto;\r\n  margin-right: auto;\r\n}\r\na.thumbnail:hover,\r\na.thumbnail:focus,\r\na.thumbnail.active {\r\n  border-color: #df691a;\r\n}\r\n.thumbnail .caption {\r\n  padding: 9px;\r\n  color: #ebebeb;\r\n}\r\n.alert {\r\n  padding: 15px;\r\n  margin-bottom: 21px;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n}\r\n.alert h4 {\r\n  margin-top: 0;\r\n  color: inherit;\r\n}\r\n.alert .alert-link {\r\n  font-weight: bold;\r\n}\r\n.alert > p,\r\n.alert > ul {\r\n  margin-bottom: 0;\r\n}\r\n.alert > p + p {\r\n  margin-top: 5px;\r\n}\r\n.alert-dismissable,\r\n.alert-dismissible {\r\n  padding-right: 35px;\r\n}\r\n.alert-dismissable .close,\r\n.alert-dismissible .close {\r\n  position: relative;\r\n  top: -2px;\r\n  right: -21px;\r\n  color: inherit;\r\n}\r\n.alert-success {\r\n  background-color: #5cb85c;\r\n  border-color: transparent;\r\n  color: #ebebeb;\r\n}\r\n.alert-success hr {\r\n  border-top-color: rgba(0, 0, 0, 0);\r\n}\r\n.alert-success .alert-link {\r\n  color: #d2d2d2;\r\n}\r\n.alert-info {\r\n  background-color: #5bc0de;\r\n  border-color: transparent;\r\n  color: #ebebeb;\r\n}\r\n.alert-info hr {\r\n  border-top-color: rgba(0, 0, 0, 0);\r\n}\r\n.alert-info .alert-link {\r\n  color: #d2d2d2;\r\n}\r\n.alert-warning {\r\n  background-color: #f0ad4e;\r\n  border-color: transparent;\r\n  color: #ebebeb;\r\n}\r\n.alert-warning hr {\r\n  border-top-color: rgba(0, 0, 0, 0);\r\n}\r\n.alert-warning .alert-link {\r\n  color: #d2d2d2;\r\n}\r\n.alert-danger {\r\n  background-color: #d9534f;\r\n  border-color: transparent;\r\n  color: #ebebeb;\r\n}\r\n.alert-danger hr {\r\n  border-top-color: rgba(0, 0, 0, 0);\r\n}\r\n.alert-danger .alert-link {\r\n  color: #d2d2d2;\r\n}\r\n@-webkit-keyframes progress-bar-stripes {\r\n  from {\r\n    background-position: 40px 0;\r\n  }\r\n  to {\r\n    background-position: 0 0;\r\n  }\r\n}\r\n@-o-keyframes progress-bar-stripes {\r\n  from {\r\n    background-position: 40px 0;\r\n  }\r\n  to {\r\n    background-position: 0 0;\r\n  }\r\n}\r\n@keyframes progress-bar-stripes {\r\n  from {\r\n    background-position: 40px 0;\r\n  }\r\n  to {\r\n    background-position: 0 0;\r\n  }\r\n}\r\n.progress {\r\n  overflow: hidden;\r\n  height: 21px;\r\n  margin-bottom: 21px;\r\n  background-color: #4e5d6c;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\r\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\r\n}\r\n.progress-bar {\r\n  float: left;\r\n  width: 0%;\r\n  height: 100%;\r\n  font-size: 13px;\r\n  line-height: 21px;\r\n  color: #ffffff;\r\n  text-align: center;\r\n  background-color: #df691a;\r\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\r\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\r\n  -webkit-transition: width 0.6s ease;\r\n  -o-transition: width 0.6s ease;\r\n  transition: width 0.6s ease;\r\n}\r\n.progress-striped .progress-bar,\r\n.progress-bar-striped {\r\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  -webkit-background-size: 40px 40px;\r\n          background-size: 40px 40px;\r\n}\r\n.progress.active .progress-bar,\r\n.progress-bar.active {\r\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\r\n  -o-animation: progress-bar-stripes 2s linear infinite;\r\n  animation: progress-bar-stripes 2s linear infinite;\r\n}\r\n.progress-bar-success {\r\n  background-color: #5cb85c;\r\n}\r\n.progress-striped .progress-bar-success {\r\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n}\r\n.progress-bar-info {\r\n  background-color: #5bc0de;\r\n}\r\n.progress-striped .progress-bar-info {\r\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n}\r\n.progress-bar-warning {\r\n  background-color: #f0ad4e;\r\n}\r\n.progress-striped .progress-bar-warning {\r\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n}\r\n.progress-bar-danger {\r\n  background-color: #d9534f;\r\n}\r\n.progress-striped .progress-bar-danger {\r\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\r\n}\r\n.media {\r\n  margin-top: 15px;\r\n}\r\n.media:first-child {\r\n  margin-top: 0;\r\n}\r\n.media,\r\n.media-body {\r\n  zoom: 1;\r\n  overflow: hidden;\r\n}\r\n.media-body {\r\n  width: 10000px;\r\n}\r\n.media-object {\r\n  display: block;\r\n}\r\n.media-right,\r\n.media > .pull-right {\r\n  padding-left: 10px;\r\n}\r\n.media-left,\r\n.media > .pull-left {\r\n  padding-right: 10px;\r\n}\r\n.media-left,\r\n.media-right,\r\n.media-body {\r\n  display: table-cell;\r\n  vertical-align: top;\r\n}\r\n.media-middle {\r\n  vertical-align: middle;\r\n}\r\n.media-bottom {\r\n  vertical-align: bottom;\r\n}\r\n.media-heading {\r\n  margin-top: 0;\r\n  margin-bottom: 5px;\r\n}\r\n.media-list {\r\n  padding-left: 0;\r\n  list-style: none;\r\n}\r\n.list-group {\r\n  margin-bottom: 20px;\r\n  padding-left: 0;\r\n}\r\n.list-group-item {\r\n  position: relative;\r\n  display: block;\r\n  padding: 10px 15px;\r\n  margin-bottom: -1px;\r\n  background-color: #4e5d6c;\r\n  border: 1px solid transparent;\r\n}\r\n.list-group-item:first-child {\r\n  border-top-right-radius: 0;\r\n  border-top-left-radius: 0;\r\n}\r\n.list-group-item:last-child {\r\n  margin-bottom: 0;\r\n  border-bottom-right-radius: 0;\r\n  border-bottom-left-radius: 0;\r\n}\r\na.list-group-item {\r\n  color: #ebebeb;\r\n}\r\na.list-group-item .list-group-item-heading {\r\n  color: #ebebeb;\r\n}\r\na.list-group-item:hover,\r\na.list-group-item:focus {\r\n  text-decoration: none;\r\n  color: #ebebeb;\r\n  background-color: #485563;\r\n}\r\n.list-group-item.disabled,\r\n.list-group-item.disabled:hover,\r\n.list-group-item.disabled:focus {\r\n  background-color: #ebebeb;\r\n  color: #4e5d6c;\r\n  cursor: not-allowed;\r\n}\r\n.list-group-item.disabled .list-group-item-heading,\r\n.list-group-item.disabled:hover .list-group-item-heading,\r\n.list-group-item.disabled:focus .list-group-item-heading {\r\n  color: inherit;\r\n}\r\n.list-group-item.disabled .list-group-item-text,\r\n.list-group-item.disabled:hover .list-group-item-text,\r\n.list-group-item.disabled:focus .list-group-item-text {\r\n  color: #4e5d6c;\r\n}\r\n.list-group-item.active,\r\n.list-group-item.active:hover,\r\n.list-group-item.active:focus {\r\n  z-index: 2;\r\n  color: #ffffff;\r\n  background-color: #df691a;\r\n  border-color: #df691a;\r\n}\r\n.list-group-item.active .list-group-item-heading,\r\n.list-group-item.active:hover .list-group-item-heading,\r\n.list-group-item.active:focus .list-group-item-heading,\r\n.list-group-item.active .list-group-item-heading > small,\r\n.list-group-item.active:hover .list-group-item-heading > small,\r\n.list-group-item.active:focus .list-group-item-heading > small,\r\n.list-group-item.active .list-group-item-heading > .small,\r\n.list-group-item.active:hover .list-group-item-heading > .small,\r\n.list-group-item.active:focus .list-group-item-heading > .small {\r\n  color: inherit;\r\n}\r\n.list-group-item.active .list-group-item-text,\r\n.list-group-item.active:hover .list-group-item-text,\r\n.list-group-item.active:focus .list-group-item-text {\r\n  color: #f9decc;\r\n}\r\n.list-group-item-success {\r\n  color: #ebebeb;\r\n  background-color: #5cb85c;\r\n}\r\na.list-group-item-success {\r\n  color: #ebebeb;\r\n}\r\na.list-group-item-success .list-group-item-heading {\r\n  color: inherit;\r\n}\r\na.list-group-item-success:hover,\r\na.list-group-item-success:focus {\r\n  color: #ebebeb;\r\n  background-color: #4cae4c;\r\n}\r\na.list-group-item-success.active,\r\na.list-group-item-success.active:hover,\r\na.list-group-item-success.active:focus {\r\n  color: #fff;\r\n  background-color: #ebebeb;\r\n  border-color: #ebebeb;\r\n}\r\n.list-group-item-info {\r\n  color: #ebebeb;\r\n  background-color: #5bc0de;\r\n}\r\na.list-group-item-info {\r\n  color: #ebebeb;\r\n}\r\na.list-group-item-info .list-group-item-heading {\r\n  color: inherit;\r\n}\r\na.list-group-item-info:hover,\r\na.list-group-item-info:focus {\r\n  color: #ebebeb;\r\n  background-color: #46b8da;\r\n}\r\na.list-group-item-info.active,\r\na.list-group-item-info.active:hover,\r\na.list-group-item-info.active:focus {\r\n  color: #fff;\r\n  background-color: #ebebeb;\r\n  border-color: #ebebeb;\r\n}\r\n.list-group-item-warning {\r\n  color: #ebebeb;\r\n  background-color: #f0ad4e;\r\n}\r\na.list-group-item-warning {\r\n  color: #ebebeb;\r\n}\r\na.list-group-item-warning .list-group-item-heading {\r\n  color: inherit;\r\n}\r\na.list-group-item-warning:hover,\r\na.list-group-item-warning:focus {\r\n  color: #ebebeb;\r\n  background-color: #eea236;\r\n}\r\na.list-group-item-warning.active,\r\na.list-group-item-warning.active:hover,\r\na.list-group-item-warning.active:focus {\r\n  color: #fff;\r\n  background-color: #ebebeb;\r\n  border-color: #ebebeb;\r\n}\r\n.list-group-item-danger {\r\n  color: #ebebeb;\r\n  background-color: #d9534f;\r\n}\r\na.list-group-item-danger {\r\n  color: #ebebeb;\r\n}\r\na.list-group-item-danger .list-group-item-heading {\r\n  color: inherit;\r\n}\r\na.list-group-item-danger:hover,\r\na.list-group-item-danger:focus {\r\n  color: #ebebeb;\r\n  background-color: #d43f3a;\r\n}\r\na.list-group-item-danger.active,\r\na.list-group-item-danger.active:hover,\r\na.list-group-item-danger.active:focus {\r\n  color: #fff;\r\n  background-color: #ebebeb;\r\n  border-color: #ebebeb;\r\n}\r\n.list-group-item-heading {\r\n  margin-top: 0;\r\n  margin-bottom: 5px;\r\n}\r\n.list-group-item-text {\r\n  margin-bottom: 0;\r\n  line-height: 1.3;\r\n}\r\n.panel {\r\n  margin-bottom: 21px;\r\n  background-color: #4e5d6c;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\r\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\r\n}\r\n.panel-body {\r\n  padding: 15px;\r\n}\r\n.panel-heading {\r\n  padding: 10px 15px;\r\n  border-bottom: 1px solid transparent;\r\n  border-top-right-radius: -1;\r\n  border-top-left-radius: -1;\r\n}\r\n.panel-heading > .dropdown .dropdown-toggle {\r\n  color: inherit;\r\n}\r\n.panel-title {\r\n  margin-top: 0;\r\n  margin-bottom: 0;\r\n  font-size: 17px;\r\n  color: inherit;\r\n}\r\n.panel-title > a,\r\n.panel-title > small,\r\n.panel-title > .small,\r\n.panel-title > small > a,\r\n.panel-title > .small > a {\r\n  color: inherit;\r\n}\r\n.panel-footer {\r\n  padding: 10px 15px;\r\n  background-color: #485563;\r\n  border-top: 1px solid transparent;\r\n  border-bottom-right-radius: -1;\r\n  border-bottom-left-radius: -1;\r\n}\r\n.panel > .list-group,\r\n.panel > .panel-collapse > .list-group {\r\n  margin-bottom: 0;\r\n}\r\n.panel > .list-group .list-group-item,\r\n.panel > .panel-collapse > .list-group .list-group-item {\r\n  border-width: 1px 0;\r\n  border-radius: 0;\r\n}\r\n.panel > .list-group:first-child .list-group-item:first-child,\r\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\r\n  border-top: 0;\r\n  border-top-right-radius: -1;\r\n  border-top-left-radius: -1;\r\n}\r\n.panel > .list-group:last-child .list-group-item:last-child,\r\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\r\n  border-bottom: 0;\r\n  border-bottom-right-radius: -1;\r\n  border-bottom-left-radius: -1;\r\n}\r\n.panel-heading + .list-group .list-group-item:first-child {\r\n  border-top-width: 0;\r\n}\r\n.list-group + .panel-footer {\r\n  border-top-width: 0;\r\n}\r\n.panel > .table,\r\n.panel > .table-responsive > .table,\r\n.panel > .panel-collapse > .table {\r\n  margin-bottom: 0;\r\n}\r\n.panel > .table caption,\r\n.panel > .table-responsive > .table caption,\r\n.panel > .panel-collapse > .table caption {\r\n  padding-left: 15px;\r\n  padding-right: 15px;\r\n}\r\n.panel > .table:first-child,\r\n.panel > .table-responsive:first-child > .table:first-child {\r\n  border-top-right-radius: -1;\r\n  border-top-left-radius: -1;\r\n}\r\n.panel > .table:first-child > thead:first-child > tr:first-child,\r\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\r\n.panel > .table:first-child > tbody:first-child > tr:first-child,\r\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\r\n  border-top-left-radius: -1;\r\n  border-top-right-radius: -1;\r\n}\r\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\r\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\r\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\r\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\r\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\r\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\r\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\r\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\r\n  border-top-left-radius: -1;\r\n}\r\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\r\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\r\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\r\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\r\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\r\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\r\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\r\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\r\n  border-top-right-radius: -1;\r\n}\r\n.panel > .table:last-child,\r\n.panel > .table-responsive:last-child > .table:last-child {\r\n  border-bottom-right-radius: -1;\r\n  border-bottom-left-radius: -1;\r\n}\r\n.panel > .table:last-child > tbody:last-child > tr:last-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\r\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\r\n  border-bottom-left-radius: -1;\r\n  border-bottom-right-radius: -1;\r\n}\r\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\r\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\r\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\r\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\r\n  border-bottom-left-radius: -1;\r\n}\r\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\r\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\r\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\r\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\r\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\r\n  border-bottom-right-radius: -1;\r\n}\r\n.panel > .panel-body + .table,\r\n.panel > .panel-body + .table-responsive,\r\n.panel > .table + .panel-body,\r\n.panel > .table-responsive + .panel-body {\r\n  border-top: 1px solid #4e5d6c;\r\n}\r\n.panel > .table > tbody:first-child > tr:first-child th,\r\n.panel > .table > tbody:first-child > tr:first-child td {\r\n  border-top: 0;\r\n}\r\n.panel > .table-bordered,\r\n.panel > .table-responsive > .table-bordered {\r\n  border: 0;\r\n}\r\n.panel > .table-bordered > thead > tr > th:first-child,\r\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\r\n.panel > .table-bordered > tbody > tr > th:first-child,\r\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\r\n.panel > .table-bordered > tfoot > tr > th:first-child,\r\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\r\n.panel > .table-bordered > thead > tr > td:first-child,\r\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\r\n.panel > .table-bordered > tbody > tr > td:first-child,\r\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\r\n.panel > .table-bordered > tfoot > tr > td:first-child,\r\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\r\n  border-left: 0;\r\n}\r\n.panel > .table-bordered > thead > tr > th:last-child,\r\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\r\n.panel > .table-bordered > tbody > tr > th:last-child,\r\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\r\n.panel > .table-bordered > tfoot > tr > th:last-child,\r\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\r\n.panel > .table-bordered > thead > tr > td:last-child,\r\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\r\n.panel > .table-bordered > tbody > tr > td:last-child,\r\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\r\n.panel > .table-bordered > tfoot > tr > td:last-child,\r\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\r\n  border-right: 0;\r\n}\r\n.panel > .table-bordered > thead > tr:first-child > td,\r\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\r\n.panel > .table-bordered > tbody > tr:first-child > td,\r\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\r\n.panel > .table-bordered > thead > tr:first-child > th,\r\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\r\n.panel > .table-bordered > tbody > tr:first-child > th,\r\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\r\n  border-bottom: 0;\r\n}\r\n.panel > .table-bordered > tbody > tr:last-child > td,\r\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\r\n.panel > .table-bordered > tfoot > tr:last-child > td,\r\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\r\n.panel > .table-bordered > tbody > tr:last-child > th,\r\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\r\n.panel > .table-bordered > tfoot > tr:last-child > th,\r\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\r\n  border-bottom: 0;\r\n}\r\n.panel > .table-responsive {\r\n  border: 0;\r\n  margin-bottom: 0;\r\n}\r\n.panel-group {\r\n  margin-bottom: 21px;\r\n}\r\n.panel-group .panel {\r\n  margin-bottom: 0;\r\n  border-radius: 0;\r\n}\r\n.panel-group .panel + .panel {\r\n  margin-top: 5px;\r\n}\r\n.panel-group .panel-heading {\r\n  border-bottom: 0;\r\n}\r\n.panel-group .panel-heading + .panel-collapse > .panel-body,\r\n.panel-group .panel-heading + .panel-collapse > .list-group {\r\n  border-top: 1px solid transparent;\r\n}\r\n.panel-group .panel-footer {\r\n  border-top: 0;\r\n}\r\n.panel-group .panel-footer + .panel-collapse .panel-body {\r\n  border-bottom: 1px solid transparent;\r\n}\r\n.panel-default {\r\n  border-color: transparent;\r\n}\r\n.panel-default > .panel-heading {\r\n  color: #333333;\r\n  background-color: #f5f5f5;\r\n  border-color: transparent;\r\n}\r\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\r\n  border-top-color: transparent;\r\n}\r\n.panel-default > .panel-heading .badge {\r\n  color: #f5f5f5;\r\n  background-color: #333333;\r\n}\r\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\r\n  border-bottom-color: transparent;\r\n}\r\n.panel-primary {\r\n  border-color: transparent;\r\n}\r\n.panel-primary > .panel-heading {\r\n  color: #ffffff;\r\n  background-color: #df691a;\r\n  border-color: transparent;\r\n}\r\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\r\n  border-top-color: transparent;\r\n}\r\n.panel-primary > .panel-heading .badge {\r\n  color: #df691a;\r\n  background-color: #ffffff;\r\n}\r\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\r\n  border-bottom-color: transparent;\r\n}\r\n.panel-success {\r\n  border-color: transparent;\r\n}\r\n.panel-success > .panel-heading {\r\n  color: #ebebeb;\r\n  background-color: #5cb85c;\r\n  border-color: transparent;\r\n}\r\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\r\n  border-top-color: transparent;\r\n}\r\n.panel-success > .panel-heading .badge {\r\n  color: #5cb85c;\r\n  background-color: #ebebeb;\r\n}\r\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\r\n  border-bottom-color: transparent;\r\n}\r\n.panel-info {\r\n  border-color: transparent;\r\n}\r\n.panel-info > .panel-heading {\r\n  color: #ebebeb;\r\n  background-color: #5bc0de;\r\n  border-color: transparent;\r\n}\r\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\r\n  border-top-color: transparent;\r\n}\r\n.panel-info > .panel-heading .badge {\r\n  color: #5bc0de;\r\n  background-color: #ebebeb;\r\n}\r\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\r\n  border-bottom-color: transparent;\r\n}\r\n.panel-warning {\r\n  border-color: transparent;\r\n}\r\n.panel-warning > .panel-heading {\r\n  color: #ebebeb;\r\n  background-color: #f0ad4e;\r\n  border-color: transparent;\r\n}\r\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\r\n  border-top-color: transparent;\r\n}\r\n.panel-warning > .panel-heading .badge {\r\n  color: #f0ad4e;\r\n  background-color: #ebebeb;\r\n}\r\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\r\n  border-bottom-color: transparent;\r\n}\r\n.panel-danger {\r\n  border-color: transparent;\r\n}\r\n.panel-danger > .panel-heading {\r\n  color: #ebebeb;\r\n  background-color: #d9534f;\r\n  border-color: transparent;\r\n}\r\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\r\n  border-top-color: transparent;\r\n}\r\n.panel-danger > .panel-heading .badge {\r\n  color: #d9534f;\r\n  background-color: #ebebeb;\r\n}\r\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\r\n  border-bottom-color: transparent;\r\n}\r\n.embed-responsive {\r\n  position: relative;\r\n  display: block;\r\n  height: 0;\r\n  padding: 0;\r\n  overflow: hidden;\r\n}\r\n.embed-responsive .embed-responsive-item,\r\n.embed-responsive iframe,\r\n.embed-responsive embed,\r\n.embed-responsive object,\r\n.embed-responsive video {\r\n  position: absolute;\r\n  top: 0;\r\n  left: 0;\r\n  bottom: 0;\r\n  height: 100%;\r\n  width: 100%;\r\n  border: 0;\r\n}\r\n.embed-responsive-16by9 {\r\n  padding-bottom: 56.25%;\r\n}\r\n.embed-responsive-4by3 {\r\n  padding-bottom: 75%;\r\n}\r\n.well {\r\n  min-height: 20px;\r\n  padding: 19px;\r\n  margin-bottom: 20px;\r\n  background-color: #4e5d6c;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\r\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\r\n}\r\n.well blockquote {\r\n  border-color: #ddd;\r\n  border-color: rgba(0, 0, 0, 0.15);\r\n}\r\n.well-lg {\r\n  padding: 24px;\r\n  border-radius: 0;\r\n}\r\n.well-sm {\r\n  padding: 9px;\r\n  border-radius: 0;\r\n}\r\n.close {\r\n  float: right;\r\n  font-size: 22.5px;\r\n  font-weight: bold;\r\n  line-height: 1;\r\n  color: #ebebeb;\r\n  text-shadow: none;\r\n  opacity: 0.2;\r\n  filter: alpha(opacity=20);\r\n}\r\n.close:hover,\r\n.close:focus {\r\n  color: #ebebeb;\r\n  text-decoration: none;\r\n  cursor: pointer;\r\n  opacity: 0.5;\r\n  filter: alpha(opacity=50);\r\n}\r\nbutton.close {\r\n  padding: 0;\r\n  cursor: pointer;\r\n  background: transparent;\r\n  border: 0;\r\n  -webkit-appearance: none;\r\n}\r\n.modal-open {\r\n  overflow: hidden;\r\n}\r\n.modal {\r\n  display: none;\r\n  overflow: hidden;\r\n  position: fixed;\r\n  top: 0;\r\n  right: 0;\r\n  bottom: 0;\r\n  left: 0;\r\n  z-index: 1050;\r\n  -webkit-overflow-scrolling: touch;\r\n  outline: 0;\r\n}\r\n.modal.fade .modal-dialog {\r\n  -webkit-transform: translate(0, -25%);\r\n  -ms-transform: translate(0, -25%);\r\n  -o-transform: translate(0, -25%);\r\n  transform: translate(0, -25%);\r\n  -webkit-transition: -webkit-transform 0.3s ease-out;\r\n  -o-transition: -o-transform 0.3s ease-out;\r\n  transition: transform 0.3s ease-out;\r\n}\r\n.modal.in .modal-dialog {\r\n  -webkit-transform: translate(0, 0);\r\n  -ms-transform: translate(0, 0);\r\n  -o-transform: translate(0, 0);\r\n  transform: translate(0, 0);\r\n}\r\n.modal-open .modal {\r\n  overflow-x: hidden;\r\n  overflow-y: auto;\r\n}\r\n.modal-dialog {\r\n  position: relative;\r\n  width: auto;\r\n  margin: 10px;\r\n}\r\n.modal-content {\r\n  position: relative;\r\n  background-color: #4e5d6c;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\r\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\r\n  -webkit-background-clip: padding-box;\r\n          background-clip: padding-box;\r\n  outline: 0;\r\n}\r\n.modal-backdrop {\r\n  position: fixed;\r\n  top: 0;\r\n  right: 0;\r\n  bottom: 0;\r\n  left: 0;\r\n  z-index: 1040;\r\n  background-color: #000000;\r\n}\r\n.modal-backdrop.fade {\r\n  opacity: 0;\r\n  filter: alpha(opacity=0);\r\n}\r\n.modal-backdrop.in {\r\n  opacity: 0.5;\r\n  filter: alpha(opacity=50);\r\n}\r\n.modal-header {\r\n  padding: 15px;\r\n  border-bottom: 1px solid #2b3e50;\r\n  min-height: 16.42857143px;\r\n}\r\n.modal-header .close {\r\n  margin-top: -2px;\r\n}\r\n.modal-title {\r\n  margin: 0;\r\n  line-height: 1.42857143;\r\n}\r\n.modal-body {\r\n  position: relative;\r\n  padding: 20px;\r\n}\r\n.modal-footer {\r\n  padding: 20px;\r\n  text-align: right;\r\n  border-top: 1px solid #2b3e50;\r\n}\r\n.modal-footer .btn + .btn {\r\n  margin-left: 5px;\r\n  margin-bottom: 0;\r\n}\r\n.modal-footer .btn-group .btn + .btn {\r\n  margin-left: -1px;\r\n}\r\n.modal-footer .btn-block + .btn-block {\r\n  margin-left: 0;\r\n}\r\n.modal-scrollbar-measure {\r\n  position: absolute;\r\n  top: -9999px;\r\n  width: 50px;\r\n  height: 50px;\r\n  overflow: scroll;\r\n}\r\n@media (min-width: 768px) {\r\n  .modal-dialog {\r\n    width: 600px;\r\n    margin: 30px auto;\r\n  }\r\n  .modal-content {\r\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\r\n    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\r\n  }\r\n  .modal-sm {\r\n    width: 300px;\r\n  }\r\n}\r\n@media (min-width: 992px) {\r\n  .modal-lg {\r\n    width: 900px;\r\n  }\r\n}\r\n.tooltip {\r\n  position: absolute;\r\n  z-index: 1070;\r\n  display: block;\r\n  font-family: \"Lato\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\r\n  font-size: 13px;\r\n  font-weight: normal;\r\n  line-height: 1.4;\r\n  opacity: 0;\r\n  filter: alpha(opacity=0);\r\n}\r\n.tooltip.in {\r\n  opacity: 0.9;\r\n  filter: alpha(opacity=90);\r\n}\r\n.tooltip.top {\r\n  margin-top: -3px;\r\n  padding: 5px 0;\r\n}\r\n.tooltip.right {\r\n  margin-left: 3px;\r\n  padding: 0 5px;\r\n}\r\n.tooltip.bottom {\r\n  margin-top: 3px;\r\n  padding: 5px 0;\r\n}\r\n.tooltip.left {\r\n  margin-left: -3px;\r\n  padding: 0 5px;\r\n}\r\n.tooltip-inner {\r\n  max-width: 200px;\r\n  padding: 3px 8px;\r\n  color: #ffffff;\r\n  text-align: center;\r\n  text-decoration: none;\r\n  background-color: #000000;\r\n  border-radius: 0;\r\n}\r\n.tooltip-arrow {\r\n  position: absolute;\r\n  width: 0;\r\n  height: 0;\r\n  border-color: transparent;\r\n  border-style: solid;\r\n}\r\n.tooltip.top .tooltip-arrow {\r\n  bottom: 0;\r\n  left: 50%;\r\n  margin-left: -5px;\r\n  border-width: 5px 5px 0;\r\n  border-top-color: #000000;\r\n}\r\n.tooltip.top-left .tooltip-arrow {\r\n  bottom: 0;\r\n  right: 5px;\r\n  margin-bottom: -5px;\r\n  border-width: 5px 5px 0;\r\n  border-top-color: #000000;\r\n}\r\n.tooltip.top-right .tooltip-arrow {\r\n  bottom: 0;\r\n  left: 5px;\r\n  margin-bottom: -5px;\r\n  border-width: 5px 5px 0;\r\n  border-top-color: #000000;\r\n}\r\n.tooltip.right .tooltip-arrow {\r\n  top: 50%;\r\n  left: 0;\r\n  margin-top: -5px;\r\n  border-width: 5px 5px 5px 0;\r\n  border-right-color: #000000;\r\n}\r\n.tooltip.left .tooltip-arrow {\r\n  top: 50%;\r\n  right: 0;\r\n  margin-top: -5px;\r\n  border-width: 5px 0 5px 5px;\r\n  border-left-color: #000000;\r\n}\r\n.tooltip.bottom .tooltip-arrow {\r\n  top: 0;\r\n  left: 50%;\r\n  margin-left: -5px;\r\n  border-width: 0 5px 5px;\r\n  border-bottom-color: #000000;\r\n}\r\n.tooltip.bottom-left .tooltip-arrow {\r\n  top: 0;\r\n  right: 5px;\r\n  margin-top: -5px;\r\n  border-width: 0 5px 5px;\r\n  border-bottom-color: #000000;\r\n}\r\n.tooltip.bottom-right .tooltip-arrow {\r\n  top: 0;\r\n  left: 5px;\r\n  margin-top: -5px;\r\n  border-width: 0 5px 5px;\r\n  border-bottom-color: #000000;\r\n}\r\n.popover {\r\n  position: absolute;\r\n  top: 0;\r\n  left: 0;\r\n  z-index: 1060;\r\n  display: none;\r\n  max-width: 276px;\r\n  padding: 1px;\r\n  font-family: \"Lato\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\r\n  font-size: 15px;\r\n  font-weight: normal;\r\n  line-height: 1.42857143;\r\n  text-align: left;\r\n  background-color: #4e5d6c;\r\n  -webkit-background-clip: padding-box;\r\n          background-clip: padding-box;\r\n  border: 1px solid transparent;\r\n  border-radius: 0;\r\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\r\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\r\n  white-space: normal;\r\n}\r\n.popover.top {\r\n  margin-top: -10px;\r\n}\r\n.popover.right {\r\n  margin-left: 10px;\r\n}\r\n.popover.bottom {\r\n  margin-top: 10px;\r\n}\r\n.popover.left {\r\n  margin-left: -10px;\r\n}\r\n.popover-title {\r\n  margin: 0;\r\n  padding: 8px 14px;\r\n  font-size: 15px;\r\n  background-color: #485563;\r\n  border-bottom: 1px solid #3d4954;\r\n  border-radius: -1 -1 0 0;\r\n}\r\n.popover-content {\r\n  padding: 9px 14px;\r\n}\r\n.popover > .arrow,\r\n.popover > .arrow:after {\r\n  position: absolute;\r\n  display: block;\r\n  width: 0;\r\n  height: 0;\r\n  border-color: transparent;\r\n  border-style: solid;\r\n}\r\n.popover > .arrow {\r\n  border-width: 11px;\r\n}\r\n.popover > .arrow:after {\r\n  border-width: 10px;\r\n  content: \"\";\r\n}\r\n.popover.top > .arrow {\r\n  left: 50%;\r\n  margin-left: -11px;\r\n  border-bottom-width: 0;\r\n  border-top-color: transparent;\r\n  bottom: -11px;\r\n}\r\n.popover.top > .arrow:after {\r\n  content: \" \";\r\n  bottom: 1px;\r\n  margin-left: -10px;\r\n  border-bottom-width: 0;\r\n  border-top-color: #4e5d6c;\r\n}\r\n.popover.right > .arrow {\r\n  top: 50%;\r\n  left: -11px;\r\n  margin-top: -11px;\r\n  border-left-width: 0;\r\n  border-right-color: transparent;\r\n}\r\n.popover.right > .arrow:after {\r\n  content: \" \";\r\n  left: 1px;\r\n  bottom: -10px;\r\n  border-left-width: 0;\r\n  border-right-color: #4e5d6c;\r\n}\r\n.popover.bottom > .arrow {\r\n  left: 50%;\r\n  margin-left: -11px;\r\n  border-top-width: 0;\r\n  border-bottom-color: transparent;\r\n  top: -11px;\r\n}\r\n.popover.bottom > .arrow:after {\r\n  content: \" \";\r\n  top: 1px;\r\n  margin-left: -10px;\r\n  border-top-width: 0;\r\n  border-bottom-color: #4e5d6c;\r\n}\r\n.popover.left > .arrow {\r\n  top: 50%;\r\n  right: -11px;\r\n  margin-top: -11px;\r\n  border-right-width: 0;\r\n  border-left-color: transparent;\r\n}\r\n.popover.left > .arrow:after {\r\n  content: \" \";\r\n  right: 1px;\r\n  border-right-width: 0;\r\n  border-left-color: #4e5d6c;\r\n  bottom: -10px;\r\n}\r\n\r\n.clearfix:before,\r\n.clearfix:after,\r\n.dl-horizontal dd:before,\r\n.dl-horizontal dd:after,\r\n.container:before,\r\n.container:after,\r\n.container-fluid:before,\r\n.container-fluid:after,\r\n.row:before,\r\n.row:after,\r\n.form-horizontal .form-group:before,\r\n.form-horizontal .form-group:after,\r\n.btn-toolbar:before,\r\n.btn-toolbar:after,\r\n.btn-group-vertical > .btn-group:before,\r\n.btn-group-vertical > .btn-group:after,\r\n.nav:before,\r\n.nav:after,\r\n.navbar:before,\r\n.navbar:after,\r\n.navbar-header:before,\r\n.navbar-header:after,\r\n.navbar-collapse:before,\r\n.navbar-collapse:after,\r\n.pager:before,\r\n.pager:after,\r\n.panel-body:before,\r\n.panel-body:after,\r\n.modal-footer:before,\r\n.modal-footer:after {\r\n  content: \" \";\r\n  display: table;\r\n}\r\n.clearfix:after,\r\n.dl-horizontal dd:after,\r\n.container:after,\r\n.container-fluid:after,\r\n.row:after,\r\n.form-horizontal .form-group:after,\r\n.btn-toolbar:after,\r\n.btn-group-vertical > .btn-group:after,\r\n.nav:after,\r\n.navbar:after,\r\n.navbar-header:after,\r\n.navbar-collapse:after,\r\n.pager:after,\r\n.panel-body:after,\r\n.modal-footer:after {\r\n  clear: both;\r\n}\r\n.center-block {\r\n  display: block;\r\n  margin-left: auto;\r\n  margin-right: auto;\r\n}\r\n.pull-right {\r\n  float: right !important;\r\n}\r\n.pull-left {\r\n  float: left !important;\r\n}\r\n.hide {\r\n  display: none !important;\r\n}\r\n.show {\r\n  display: block !important;\r\n}\r\n.invisible {\r\n  visibility: hidden;\r\n}\r\n.text-hide {\r\n  font: 0/0 a;\r\n  color: transparent;\r\n  text-shadow: none;\r\n  background-color: transparent;\r\n  border: 0;\r\n}\r\n.hidden {\r\n  display: none !important;\r\n}\r\n.affix {\r\n  position: fixed;\r\n}\r\n@-ms-viewport {\r\n  width: device-width;\r\n}\r\n.visible-xs,\r\n.visible-sm,\r\n.visible-md,\r\n.visible-lg {\r\n  display: none !important;\r\n}\r\n.visible-xs-block,\r\n.visible-xs-inline,\r\n.visible-xs-inline-block,\r\n.visible-sm-block,\r\n.visible-sm-inline,\r\n.visible-sm-inline-block,\r\n.visible-md-block,\r\n.visible-md-inline,\r\n.visible-md-inline-block,\r\n.visible-lg-block,\r\n.visible-lg-inline,\r\n.visible-lg-inline-block {\r\n  display: none !important;\r\n}\r\n@media (max-width: 767px) {\r\n  .visible-xs {\r\n    display: block !important;\r\n  }\r\n  table.visible-xs {\r\n    display: table;\r\n  }\r\n  tr.visible-xs {\r\n    display: table-row !important;\r\n  }\r\n  th.visible-xs,\r\n  td.visible-xs {\r\n    display: table-cell !important;\r\n  }\r\n}\r\n@media (max-width: 767px) {\r\n  .visible-xs-block {\r\n    display: block !important;\r\n  }\r\n}\r\n@media (max-width: 767px) {\r\n  .visible-xs-inline {\r\n    display: inline !important;\r\n  }\r\n}\r\n@media (max-width: 767px) {\r\n  .visible-xs-inline-block {\r\n    display: inline-block !important;\r\n  }\r\n}\r\n@media (min-width: 768px) and (max-width: 991px) {\r\n  .visible-sm {\r\n    display: block !important;\r\n  }\r\n  table.visible-sm {\r\n    display: table;\r\n  }\r\n  tr.visible-sm {\r\n    display: table-row !important;\r\n  }\r\n  th.visible-sm,\r\n  td.visible-sm {\r\n    display: table-cell !important;\r\n  }\r\n}\r\n@media (min-width: 768px) and (max-width: 991px) {\r\n  .visible-sm-block {\r\n    display: block !important;\r\n  }\r\n}\r\n@media (min-width: 768px) and (max-width: 991px) {\r\n  .visible-sm-inline {\r\n    display: inline !important;\r\n  }\r\n}\r\n@media (min-width: 768px) and (max-width: 991px) {\r\n  .visible-sm-inline-block {\r\n    display: inline-block !important;\r\n  }\r\n}\r\n@media (min-width: 992px) and (max-width: 1199px) {\r\n  .visible-md {\r\n    display: block !important;\r\n  }\r\n  table.visible-md {\r\n    display: table;\r\n  }\r\n  tr.visible-md {\r\n    display: table-row !important;\r\n  }\r\n  th.visible-md,\r\n  td.visible-md {\r\n    display: table-cell !important;\r\n  }\r\n}\r\n@media (min-width: 992px) and (max-width: 1199px) {\r\n  .visible-md-block {\r\n    display: block !important;\r\n  }\r\n}\r\n@media (min-width: 992px) and (max-width: 1199px) {\r\n  .visible-md-inline {\r\n    display: inline !important;\r\n  }\r\n}\r\n@media (min-width: 992px) and (max-width: 1199px) {\r\n  .visible-md-inline-block {\r\n    display: inline-block !important;\r\n  }\r\n}\r\n@media (min-width: 1200px) {\r\n  .visible-lg {\r\n    display: block !important;\r\n  }\r\n  table.visible-lg {\r\n    display: table;\r\n  }\r\n  tr.visible-lg {\r\n    display: table-row !important;\r\n  }\r\n  th.visible-lg,\r\n  td.visible-lg {\r\n    display: table-cell !important;\r\n  }\r\n}\r\n@media (min-width: 1200px) {\r\n  .visible-lg-block {\r\n    display: block !important;\r\n  }\r\n}\r\n@media (min-width: 1200px) {\r\n  .visible-lg-inline {\r\n    display: inline !important;\r\n  }\r\n}\r\n@media (min-width: 1200px) {\r\n  .visible-lg-inline-block {\r\n    display: inline-block !important;\r\n  }\r\n}\r\n@media (max-width: 767px) {\r\n  .hidden-xs {\r\n    display: none !important;\r\n  }\r\n}\r\n@media (min-width: 768px) and (max-width: 991px) {\r\n  .hidden-sm {\r\n    display: none !important;\r\n  }\r\n}\r\n@media (min-width: 992px) and (max-width: 1199px) {\r\n  .hidden-md {\r\n    display: none !important;\r\n  }\r\n}\r\n@media (min-width: 1200px) {\r\n  .hidden-lg {\r\n    display: none !important;\r\n  }\r\n}\r\n.visible-print {\r\n  display: none !important;\r\n}\r\n@media print {\r\n  .visible-print {\r\n    display: block !important;\r\n  }\r\n  table.visible-print {\r\n    display: table;\r\n  }\r\n  tr.visible-print {\r\n    display: table-row !important;\r\n  }\r\n  th.visible-print,\r\n  td.visible-print {\r\n    display: table-cell !important;\r\n  }\r\n}\r\n.visible-print-block {\r\n  display: none !important;\r\n}\r\n@media print {\r\n  .visible-print-block {\r\n    display: block !important;\r\n  }\r\n}\r\n.visible-print-inline {\r\n  display: none !important;\r\n}\r\n@media print {\r\n  .visible-print-inline {\r\n    display: inline !important;\r\n  }\r\n}\r\n.visible-print-inline-block {\r\n  display: none !important;\r\n}\r\n@media print {\r\n  .visible-print-inline-block {\r\n    display: inline-block !important;\r\n  }\r\n}\r\n@media print {\r\n  .hidden-print {\r\n    display: none !important;\r\n  }\r\n}\r\n.navbar {\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n  border: none;\r\n  font-size: 12px;\r\n}\r\n.navbar-default .badge {\r\n  background-color: #fff;\r\n  color: #4e5d6c;\r\n}\r\n.navbar-inverse .badge {\r\n  background-color: #fff;\r\n  color: #df691a;\r\n}\r\n.btn {\r\n  font-weight: 300;\r\n}\r\n.btn-default:hover {\r\n  background-color: #485563;\r\n}\r\n.btn-sm,\r\n.btn-xs {\r\n  font-size: 12px;\r\n}\r\nbody {\r\n  font-weight: 300;\r\n}\r\n.text-primary,\r\n.text-primary:hover {\r\n  color: #df691a;\r\n}\r\n.text-success,\r\n.text-success:hover {\r\n  color: #5cb85c;\r\n}\r\n.text-danger,\r\n.text-danger:hover {\r\n  color: #d9534f;\r\n}\r\n.text-warning,\r\n.text-warning:hover {\r\n  color: #f0ad4e;\r\n}\r\n.text-info,\r\n.text-info:hover {\r\n  color: #5bc0de;\r\n}\r\n.page-header {\r\n  border-bottom-color: #4e5d6c;\r\n}\r\n.dropdown-menu {\r\n  border: none;\r\n  margin: 0;\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n}\r\n.dropdown-menu > li > a {\r\n  font-size: 12px;\r\n  font-weight: 300;\r\n}\r\n.btn-group.open .dropdown-toggle {\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n}\r\n.dropdown-header {\r\n  font-size: 12px;\r\n}\r\ntable,\r\n.table {\r\n  font-size: 15px;\r\n}\r\ntable a:not(.btn),\r\n.table a:not(.btn) {\r\n  color: #fff;\r\n  text-decoration: underline;\r\n}\r\ntable .dropdown-menu a,\r\n.table .dropdown-menu a {\r\n  text-decoration: none;\r\n}\r\ntable .text-muted,\r\n.table .text-muted {\r\n  color: #4e5d6c;\r\n}\r\ntable > thead > tr > th,\r\n.table > thead > tr > th,\r\ntable > tbody > tr > th,\r\n.table > tbody > tr > th,\r\ntable > tfoot > tr > th,\r\n.table > tfoot > tr > th,\r\ntable > thead > tr > td,\r\n.table > thead > tr > td,\r\ntable > tbody > tr > td,\r\n.table > tbody > tr > td,\r\ntable > tfoot > tr > td,\r\n.table > tfoot > tr > td {\r\n  border-color: transparent;\r\n}\r\ninput,\r\ntextarea {\r\n  color: #2b3e50;\r\n}\r\nlabel,\r\n.radio label,\r\n.checkbox label,\r\n.help-block {\r\n  font-size: 12px;\r\n  font-weight: 300;\r\n}\r\n.input-addon,\r\n.input-group-addon {\r\n  color: #ebebeb;\r\n}\r\n.has-warning .help-block,\r\n.has-warning .control-label,\r\n.has-warning .form-control-feedback {\r\n  color: #f0ad4e;\r\n}\r\n.has-warning .input-group-addon {\r\n  border: none;\r\n}\r\n.has-error .help-block,\r\n.has-error .control-label,\r\n.has-error .form-control-feedback {\r\n  color: #d9534f;\r\n}\r\n.has-error .input-group-addon {\r\n  border: none;\r\n}\r\n.has-success .help-block,\r\n.has-success .control-label,\r\n.has-success .form-control-feedback {\r\n  color: #5cb85c;\r\n}\r\n.has-success .input-group-addon {\r\n  border: none;\r\n}\r\n.form-control:focus {\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n}\r\n.has-warning .form-control:focus,\r\n.has-error .form-control:focus,\r\n.has-success .form-control:focus {\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n}\r\n.nav .open > a,\r\n.nav .open > a:hover,\r\n.nav .open > a:focus {\r\n  border-color: transparent;\r\n}\r\n.nav-tabs > li > a {\r\n  color: #ebebeb;\r\n}\r\n.nav-pills > li > a {\r\n  color: #ebebeb;\r\n}\r\n.pager a {\r\n  color: #ebebeb;\r\n}\r\n.label {\r\n  font-weight: 300;\r\n}\r\n.alert {\r\n  color: #fff;\r\n}\r\n.alert a,\r\n.alert .alert-link {\r\n  color: #fff;\r\n}\r\n.close {\r\n  opacity: 0.4;\r\n}\r\n.close:hover,\r\n.close:focus {\r\n  opacity: 1;\r\n}\r\n.well {\r\n  -webkit-box-shadow: none;\r\n  box-shadow: none;\r\n}\r\na.list-group-item.active,\r\na.list-group-item.active:hover,\r\na.list-group-item.active:focus {\r\n  border: none;\r\n}\r\na.list-group-item-success.active {\r\n  background-color: #5cb85c;\r\n}\r\na.list-group-item-success.active:hover,\r\na.list-group-item-success.active:focus {\r\n  background-color: #4cae4c;\r\n}\r\na.list-group-item-warning.active {\r\n  background-color: #f0ad4e;\r\n}\r\na.list-group-item-warning.active:hover,\r\na.list-group-item-warning.active:focus {\r\n  background-color: #eea236;\r\n}\r\na.list-group-item-danger.active {\r\n  background-color: #d9534f;\r\n}\r\na.list-group-item-danger.active:hover,\r\na.list-group-item-danger.active:focus {\r\n  background-color: #d43f3a;\r\n}\r\n.panel {\r\n  border: none;\r\n}\r\n.panel-default > .panel-heading {\r\n  background-color: #485563;\r\n  color: #ebebeb;\r\n}\r\n.thumbnail {\r\n  background-color: #4e5d6c;\r\n  border: none;\r\n}\r\n.modal {\r\n  padding: 0;\r\n  background-color:rgba(0,0,0,0.6) ;\r\n}\r\n.modal-header,\r\n.modal-footer {\r\n  background-color: #485563;\r\n  border: none;\r\n  border-radius: 0;\r\n}\r\n.popover-title {\r\n  border: none;\r\n}"
  },
  {
    "path": "app/http/html/bootstrap.css",
    "content": "html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}hr{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{background:0 0!important;color:#000!important;-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:\" (\" attr(href) \")\"}abbr[title]:after{content:\" (\" attr(title) \")\"}a[href^=\"javascript:\"]:after,a[href^=\"#\"]:after{content:\"\"}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:Lato,\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:15px;line-height:1.42857143;color:#ebebeb;background-color:#2b3e50}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#df691a;text-decoration:none}a:focus,a:hover{color:#df691a;text-decoration:underline}a:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:0}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#2b3e50;border:1px solid #ddd;border-radius:0;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:21px;margin-bottom:21px;border:0;border-top:1px solid #596a7b}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:300;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#ebebeb}.h1,.h2,.h3,h1,h2,h3{margin-top:21px;margin-bottom:10.5px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10.5px;margin-bottom:10.5px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:39px}.h2,h2{font-size:32px}.h3,h3{font-size:26px}.h4,h4{font-size:19px}.h5,h5{font-size:15px}.h6,h6{font-size:13px}p{margin:0 0 10.5px}.lead{margin-bottom:21px;font-size:17px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:22.5px}}.small,small{font-size:86%}.mark,mark{background-color:#f0ad4e;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#4e5d6c}a.text-primary:hover{color:#b15315}a.text-success:hover{color:#d2d2d2}a.text-info:hover{color:#d2d2d2}a.text-warning:hover{color:#d2d2d2}a.text-danger:hover{color:#d2d2d2}.bg-primary{color:#fff;background-color:#df691a}a.bg-primary:hover{background-color:#b15315}.bg-success{background-color:#5cb85c}a.bg-success:hover{background-color:#449d44}.bg-info{background-color:#5bc0de}a.bg-info:hover{background-color:#31b0d5}.bg-warning{background-color:#f0ad4e}a.bg-warning:hover{background-color:#ec971f}.bg-danger{background-color:#d9534f}a.bg-danger:hover{background-color:#c9302c}.page-header{padding-bottom:9.5px;margin:42px 0 21px;border-bottom:1px solid #ebebeb}ol,ul{margin-top:0;margin-bottom:10.5px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:21px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #4e5d6c}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10.5px 21px;margin:0 0 21px;font-size:18.75px;border-left:5px solid #4e5d6c}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#ebebeb}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\\2014 \\00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #4e5d6c;border-left:0;text-align:right}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\\00A0 \\2014'}address{margin-bottom:21px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,\"Courier New\",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:0}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:0;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:10px;margin:0 0 10.5px;font-size:14px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:0}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container,.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:6px;padding-bottom:6px;color:#4e5d6c;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:21px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:10px;line-height:1.42857143;vertical-align:top;border-top:1px solid #4e5d6c}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #4e5d6c}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #4e5d6c}.table .table{background-color:#2b3e50}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:3px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #4e5d6c}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#4e5d6c}.table-hover>tbody>tr:hover{background-color:#485563}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#485563}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#3d4954}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#5cb85c}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#4cae4c}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#5bc0de}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#46b8da}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#f0ad4e}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#eea236}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#d9534f}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#d43f3a}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15.75px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #4e5d6c}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:21px;font-size:22.5px;line-height:inherit;color:#ebebeb;border:0;border-bottom:1px solid #4e5d6c}label{display:inline-block;max-width:100%;margin-bottom:5px}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}output{display:block;padding-top:9px;font-size:15px;line-height:1.42857143;color:#2b3e50}.form-control{display:block;width:100%;height:39px;padding:8px 16px;font-size:15px;line-height:1.42857143;color:#2b3e50;background-color:#fff;background-image:none;border:1px solid transparent;border-radius:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:transparent;outline:0}.form-control::-moz-placeholder{color:#ccc;opacity:1}.form-control:-ms-input-placeholder{color:#ccc}.form-control::-webkit-input-placeholder{color:#ccc}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#ebebeb;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:39px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:31px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:52px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:21px;padding-left:20px;margin-bottom:0;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.form-control-static{padding-top:9px;padding-bottom:9px;margin-bottom:0;min-height:36px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm{height:31px;padding:5px 10px;font-size:13px;line-height:1.5;border-radius:0}select.input-sm{height:31px;line-height:31px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:31px;padding:5px 10px;font-size:13px;line-height:1.5;border-radius:0}select.form-group-sm .form-control{height:31px;line-height:31px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:31px;padding:5px 10px;font-size:13px;line-height:1.5;min-height:34px}.input-lg{height:52px;padding:12px 24px;font-size:19px;line-height:1.3333333;border-radius:0}select.input-lg{height:52px;line-height:52px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:52px;padding:12px 24px;font-size:19px;line-height:1.3333333;border-radius:0}select.form-group-lg .form-control{height:52px;line-height:52px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:52px;padding:12px 24px;font-size:19px;line-height:1.3333333;min-height:40px}.has-feedback{position:relative}.has-feedback .form-control{padding-right:48.75px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:39px;height:39px;line-height:39px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:52px;height:52px;line-height:52px}.input-sm+.form-control-feedback{width:31px;height:31px;line-height:31px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#ebebeb}.has-success .form-control{border-color:#ebebeb;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#d2d2d2}.has-success .input-group-addon{color:#ebebeb;background-color:#5cb85c}.has-success .form-control-feedback,.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#ebebeb}.has-warning .form-control{border-color:#ebebeb;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#d2d2d2}.has-warning .input-group-addon{color:#ebebeb;background-color:#f0ad4e}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label,.has-warning .form-control-feedback{color:#ebebeb}.has-error .form-control{border-color:#ebebeb;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#d2d2d2}.has-error .input-group-addon{color:#ebebeb;background-color:#d9534f}.has-feedback label~.form-control-feedback{top:26px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#fff}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:9px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:30px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:9px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:17px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;margin-bottom:0;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:8px 16px;font-size:15px;line-height:1.42857143;border-radius:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#fff;text-decoration:none}.btn.active,.btn:active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#fff;background-color:#4e5d6c;border-color:transparent}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#fff;background-color:#39444e;border-color:transparent}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#4e5d6c;border-color:transparent}.btn-default .badge{color:#4e5d6c;background-color:#fff}.btn-primary{color:#fff;background-color:#df691a;border-color:transparent}.btn-primary.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#b15315;border-color:transparent}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#df691a;border-color:transparent}.btn-primary .badge{color:#df691a;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:transparent}.btn-success.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:transparent}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:transparent}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:transparent}.btn-info.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:transparent}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:transparent}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:transparent}.btn-warning.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:transparent}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:transparent}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:transparent}.btn-danger.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:transparent}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:transparent}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#df691a;font-weight:400;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#df691a;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#4e5d6c;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:12px 24px;font-size:19px;line-height:1.3333333;border-radius:0}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:13px;line-height:1.5;border-radius:0}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:13px;line-height:1.5;border-radius:0}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;list-style:none;font-size:15px;text-align:left;background-color:#4e5d6c;border-radius:0;-webkit-background-clip:padding-box;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#2b3e50}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;line-height:1.42857143;color:#ebebeb;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#ebebeb;background-color:#485563}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#df691a}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#2b3e50}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;line-height:1.42857143;color:#2b3e50;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:\"\"}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:0;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:52px;padding:12px 24px;font-size:19px;line-height:1.3333333;border-radius:0}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:52px;line-height:52px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:31px;padding:5px 10px;font-size:13px;line-height:1.5;border-radius:0}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:31px;line-height:31px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:8px 16px;font-size:15px;font-weight:400;line-height:1;text-align:center;background-color:#4e5d6c;border:1px solid transparent;border-radius:0}.input-group-addon.input-sm{padding:5px 10px;font-size:13px;border-radius:0}.input-group-addon.input-lg{padding:12px 24px;font-size:19px;border-radius:0}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#4e5d6c}.nav>li.disabled>a{color:#4e5d6c}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#4e5d6c;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#4e5d6c}.nav .nav-divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid transparent}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:0}.nav-tabs>li>a:hover{border-color:#4e5d6c #4e5d6c transparent}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#ebebeb;background-color:#2b3e50;border:1px solid #4e5d6c;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #4e5d6c}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #4e5d6c;border-radius:0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#4e5d6c}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:0}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#df691a}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #4e5d6c}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #4e5d6c;border-radius:0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#4e5d6c}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:40px;margin-bottom:21px}@media (min-width:768px){.navbar{border-radius:0}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:9.5px 15px;font-size:19px;line-height:21px;height:40px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:3px;margin-bottom:3px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:0}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:4.75px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:21px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:21px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:9.5px;padding-bottom:9.5px}}.navbar-form{margin:.5px -15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:0}.navbar-btn{margin-top:.5px;margin-bottom:.5px}.navbar-btn.btn-sm{margin-top:4.5px;margin-bottom:4.5px}.navbar-btn.btn-xs{margin-top:9px;margin-bottom:9px}.navbar-text{margin-top:9.5px;margin-bottom:9.5px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#4e5d6c;border-color:transparent}.navbar-default .navbar-brand{color:#ebebeb}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#ebebeb;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#ebebeb}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#ebebeb;background-color:#485563}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:transparent}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#485563}.navbar-default .navbar-toggle .icon-bar{background-color:#ebebeb}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:transparent}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{background-color:#485563;color:#ebebeb}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#ebebeb}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#ebebeb;background-color:#485563}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .btn-link,.navbar-default .btn-link:focus,.navbar-default .btn-link:hover,.navbar-default .navbar-link,.navbar-default .navbar-link:hover{color:#ebebeb}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#df691a;border-color:transparent}.navbar-inverse .navbar-brand{color:#ebebeb}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#ebebeb;background-color:transparent}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#ebebeb}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#ebebeb;background-color:#c85e17}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:transparent}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#c85e17}.navbar-inverse .navbar-toggle .icon-bar{background-color:#ebebeb}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#bf5a16}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{background-color:#c85e17;color:#ebebeb}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#ebebeb}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#ebebeb;background-color:#c85e17}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .btn-link,.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover,.navbar-inverse .navbar-link,.navbar-inverse .navbar-link:hover{color:#ebebeb}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:21px;list-style:none;background-color:#4e5d6c;border-radius:0}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:\"/\\00a0\";padding:0 5px;color:#ebebeb}.breadcrumb>.active{color:#ebebeb}.pagination{display:inline-block;padding-left:0;margin:21px 0;border-radius:0}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:8px 16px;line-height:1.42857143;text-decoration:none;color:#ebebeb;background-color:#4e5d6c;border:1px solid transparent;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:0;border-top-left-radius:0}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#ebebeb;background-color:#485563;border-color:transparent}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#ebebeb;background-color:#df691a;border-color:transparent;cursor:default}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#323c46;background-color:#4e5d6c;border-color:transparent;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:12px 24px;font-size:19px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:0;border-top-left-radius:0}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:13px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:0;border-top-left-radius:0}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:0;border-top-right-radius:0}.pager{padding-left:0;margin:21px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#4e5d6c;border:1px solid transparent;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#485563}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#323c46;background-color:#4e5d6c;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#4e5d6c}.label-default[href]:focus,.label-default[href]:hover{background-color:#39444e}.label-primary{background-color:#df691a}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#b15315}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:13px;font-weight:300;color:#ebebeb;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#4e5d6c;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#df691a;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#4e5d6c}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:23px;font-weight:200}.jumbotron>hr{border-top-color:#39444e}.container .jumbotron,.container-fluid .jumbotron{border-radius:0}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron .h1,.jumbotron h1{font-size:67.5px}}.thumbnail{display:block;padding:4px;margin-bottom:21px;line-height:1.42857143;border-radius:0;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-left:auto;margin-right:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#df691a}.thumbnail .caption{padding:9px;color:#ebebeb}.alert{padding:15px;margin-bottom:21px;border:1px solid transparent;border-radius:0}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#5cb85c;border-color:transparent;color:#ebebeb}.alert-success hr{border-top-color:transparent}.alert-success .alert-link{color:#d2d2d2}.alert-info{background-color:#5bc0de;border-color:transparent;color:#ebebeb}.alert-info hr{border-top-color:transparent}.alert-info .alert-link{color:#d2d2d2}.alert-warning{background-color:#f0ad4e;border-color:transparent;color:#ebebeb}.alert-warning hr{border-top-color:transparent}.alert-warning .alert-link{color:#d2d2d2}.alert-danger{background-color:#d9534f;border-color:transparent;color:#ebebeb}.alert-danger hr{border-top-color:transparent}.alert-danger .alert-link{color:#d2d2d2}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:21px;margin-bottom:21px;background-color:#4e5d6c;border-radius:0;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:13px;line-height:21px;color:#fff;text-align:center;background-color:#df691a;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#4e5d6c;border:1px solid transparent}.list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}a.list-group-item,a.list-group-item .list-group-item-heading{color:#ebebeb}a.list-group-item:focus,a.list-group-item:hover{text-decoration:none;color:#ebebeb;background-color:#485563}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{background-color:#ebebeb;color:#4e5d6c;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#4e5d6c}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#df691a;border-color:#df691a}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#f9decc}.list-group-item-success{color:#ebebeb;background-color:#5cb85c}a.list-group-item-success{color:#ebebeb}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#ebebeb;background-color:#4cae4c}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;border-color:#ebebeb}.list-group-item-info{color:#ebebeb;background-color:#5bc0de}a.list-group-item-info{color:#ebebeb}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#ebebeb;background-color:#46b8da}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#ebebeb;border-color:#ebebeb}.list-group-item-warning{color:#ebebeb;background-color:#f0ad4e}a.list-group-item-warning{color:#ebebeb}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#ebebeb;background-color:#eea236}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;border-color:#ebebeb}.list-group-item-danger{color:#ebebeb;background-color:#d9534f}a.list-group-item-danger{color:#ebebeb}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#ebebeb;background-color:#d43f3a}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;border-color:#ebebeb}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:21px;background-color:#4e5d6c;border-radius:0;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:-1;border-top-left-radius:-1}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:17px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#485563;border-top:1px solid transparent;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:-1;border-top-left-radius:-1}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:-1;border-bottom-left-radius:-1}.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-left:15px;padding-right:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-right-radius:-1;border-top-left-radius:-1}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:-1;border-top-right-radius:-1}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:-1}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:-1}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:-1;border-bottom-left-radius:-1}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:-1;border-bottom-right-radius:-1}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:-1}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:-1}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #4e5d6c}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:21px}.panel-group .panel{margin-bottom:0;border-radius:0}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid transparent}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid transparent}.panel-default,.panel-default>.panel-heading{border-color:transparent}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:transparent}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:transparent}.panel-primary{border-color:transparent}.panel-primary>.panel-heading{color:#fff;background-color:#df691a;border-color:transparent}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:transparent}.panel-primary>.panel-heading .badge{color:#df691a;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:transparent}.panel-success{border-color:transparent}.panel-success>.panel-heading{color:#ebebeb;background-color:#5cb85c;border-color:transparent}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:transparent}.panel-success>.panel-heading .badge{color:#5cb85c;background-color:#ebebeb}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:transparent}.panel-info{border-color:transparent}.panel-info>.panel-heading{color:#ebebeb;background-color:#5bc0de;border-color:transparent}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:transparent}.panel-info>.panel-heading .badge{color:#5bc0de;background-color:#ebebeb}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:transparent}.panel-warning{border-color:transparent}.panel-warning>.panel-heading{color:#ebebeb;background-color:#f0ad4e;border-color:transparent}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:transparent}.panel-warning>.panel-heading .badge{color:#f0ad4e;background-color:#ebebeb}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:transparent}.panel-danger{border-color:transparent}.panel-danger>.panel-heading{color:#ebebeb;background-color:#d9534f;border-color:transparent}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:transparent}.panel-danger>.panel-heading .badge{color:#d9534f;background-color:#ebebeb}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:transparent}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#4e5d6c;border:1px solid transparent;border-radius:0}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:0}.well-sm{padding:9px;border-radius:0}.close{float:right;font-size:22.5px;font-weight:700;line-height:1;color:#ebebeb;text-shadow:none;filter:alpha(opacity=20)}.close:focus,.close:hover{color:#ebebeb;text-decoration:none;cursor:pointer;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#4e5d6c;border:1px solid transparent;border-radius:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);-webkit-background-clip:padding-box;background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;min-height:16.43px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:20px}.modal-footer{padding:20px;text-align:right}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Lato,\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:13px;font-weight:400;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:0}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:Lato,\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:15px;font-weight:400;line-height:1.42857143;text-align:left;background-color:#4e5d6c;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid transparent;border-radius:0;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:15px;background-color:#485563;border-radius:-1 -1 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:\"\"}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:transparent;bottom:-11px}.popover.top>.arrow:after{content:\" \";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#4e5d6c}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:transparent}.popover.right>.arrow:after{content:\" \";left:1px;bottom:-10px;border-left-width:0;border-right-color:#4e5d6c}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:transparent;top:-11px}.popover.bottom>.arrow:after{content:\" \";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#4e5d6c}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:transparent}.popover.left>.arrow:after{content:\" \";right:1px;border-right-width:0;border-left-color:#4e5d6c;bottom:-10px}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{content:\" \";display:table}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-print,.visible-print-block,.visible-print-inline,.visible-print-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}@media print{.visible-print-block{display:block!important}}@media print{.visible-print-inline{display:inline!important}}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}.navbar{-webkit-box-shadow:none;box-shadow:none;border:none;font-size:12px}.navbar-default .badge{background-color:#fff;color:#4e5d6c}.navbar-inverse .badge{background-color:#fff;color:#df691a}.btn{font-weight:300}.btn-default:hover{background-color:#485563}.btn-sm,.btn-xs{font-size:12px}body{font-weight:300}.text-primary,.text-primary:hover{color:#df691a}.text-success,.text-success:hover{color:#5cb85c}.text-danger,.text-danger:hover{color:#d9534f}.text-warning,.text-warning:hover{color:#f0ad4e}.text-info,.text-info:hover{color:#5bc0de}.page-header{border-bottom-color:#4e5d6c}.dropdown-menu{border:none;margin:0;-webkit-box-shadow:none;box-shadow:none}.dropdown-menu>li>a{font-size:12px;font-weight:300}.btn-group.open .dropdown-toggle{-webkit-box-shadow:none;box-shadow:none}.dropdown-header{font-size:12px}.table,table{font-size:15px}.table a:not(.btn),table a:not(.btn){color:#fff;text-decoration:underline}.table .dropdown-menu a,table .dropdown-menu a{text-decoration:none}.table .text-muted,table .text-muted{color:#4e5d6c}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th,table>tbody>tr>td,table>tbody>tr>th,table>tfoot>tr>td,table>tfoot>tr>th,table>thead>tr>td,table>thead>tr>th{border-color:transparent}input,textarea{color:#2b3e50}.checkbox label,.help-block,.radio label,label{font-size:12px;font-weight:300}.input-addon,.input-group-addon{color:#ebebeb}.has-warning .control-label,.has-warning .form-control-feedback,.has-warning .help-block{color:#f0ad4e}.has-warning .input-group-addon{border:none}.has-error .control-label,.has-error .form-control-feedback,.has-error .help-block{color:#d9534f}.has-error .input-group-addon{border:none}.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block{color:#5cb85c}.has-success .input-group-addon{border:none}.form-control:focus,.has-error .form-control:focus,.has-success .form-control:focus,.has-warning .form-control:focus{-webkit-box-shadow:none;box-shadow:none}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{border-color:transparent}.nav-pills>li>a,.nav-tabs>li>a,.pager a{color:#ebebeb}.label{font-weight:300}.alert,.alert .alert-link,.alert a{color:#fff}.close{opacity:.4}.close:focus,.close:hover{opacity:1}.well{-webkit-box-shadow:none;box-shadow:none}a.list-group-item.active,a.list-group-item.active:focus,a.list-group-item.active:hover{border:none}a.list-group-item-success.active{background-color:#5cb85c}a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{background-color:#4cae4c}a.list-group-item-warning.active{background-color:#f0ad4e}a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{background-color:#eea236}a.list-group-item-danger.active{background-color:#d9534f}a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{background-color:#d43f3a}.panel{border:none}.panel-default>.panel-heading{background-color:#485563;color:#ebebeb}.thumbnail{background-color:#4e5d6c;border:none}.modal{padding:0;background-color:rgba(0,0,0,.6)}.modal-footer,.modal-header{background-color:#485563;border:none;border-radius:0}.popover-title{border:none}"
  },
  {
    "path": "app/http/html/cats.html",
    "content": "<html>\r\n\r\n<head>\r\n  <title>Smart Relay</title>\r\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n  <link rel=\"stylesheet\" href=\"bootstrap.css\"> \r\n  </head>\r\n  <body>\r\n  \t<nav class=\"navbar-inverse navbar-default\">\r\n\t  <div class=\"container-fluid\">\r\n\t    <div class=\"navbar-header\">\t     \r\n\t      <a class=\"navbar-brand\" href=\"#\"></a>\r\n\t    </div>\r\n\t    <div class=\"collapse navbar-collapse\" id=\"bs-example-navbar-collapse-1\">\r\n                    <ul class=\"nav navbar-nav\">\r\n                     <li ><a href=\"/\">Config</a></li>\r\n                     <li ><a href=\"/speed-test\">Speed Test</a></li>\r\n                     <li class=\"active\"><a href=\"/cats\">Cats</a></li>                     \r\n                    </ul>                  \r\n                   \r\n        </div>\r\n\t  </div>\r\n\t</nav>\r\n\t\r\n\t<div class=\"container\">\r\n\t\t\r\n\t\t<h1>Smart Relay</h1>\r\n\t\t<div class=\"page-header\">\r\n\t\t\t\t<h3>Required pictures of cats</h3>\r\n\t\t</div>\r\n\t\t<img src=\"cat.jpg\" />\r\n\r\n\t</div>\r\n\t<div id=\"relay-test\" style=\"margin-bottom:30px\"></div>\r\n\r\n\t<script src=\"lib.js\" type=\"text/javascript\"></script>\t\t\r\n\r\n  </body>\r\n </html>"
  },
  {
    "path": "app/http/html/index.html",
    "content": "\r\n<html>\r\n\r\n<head>\r\n  <title>Smart Relay</title>\r\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n  <link rel=\"stylesheet\" href=\"bootstrap.css\">\r\n  <style type=\"text/css\">\r\n  \ttr:hover{\r\n  \t\tcursor:pointer;\r\n  \t}\r\n  </style>\r\n  </head>\r\n  <body>\r\n  \t<nav class=\"navbar-inverse navbar-default\">\r\n\t  <div class=\"container-fluid\">\r\n\t    <div class=\"navbar-header\">\t     \r\n\t      <a class=\"navbar-brand\" href=\"#\"></a>\r\n\t    </div>\r\n\t    <div class=\"collapse navbar-collapse\" id=\"bs-example-navbar-collapse-1\">\r\n                    <ul class=\"nav navbar-nav\">\r\n                     <li class=\"active\"><a href=\"/\">Config</a></li>\r\n                     <li><a href=\"/speed-test\">Speed Test</a></li>\r\n                     <li ><a href=\"/cats\">Cats</a></li>                          \r\n                    </ul>                  \r\n                   \r\n        </div>\r\n\t  </div>\r\n\t</nav>\r\n\t\r\n\t<div class=\"container\">\r\n\t\t\r\n\t\t<h1>Smart Relay</h1>\r\n                \r\n\t\t<div id=\"network-status\">\r\n\t        <div class=\"page-header\">\r\n\t\t\t\t<h3>Status</h3>\r\n\t\t\t</div>\r\n       \t\t <ul class=\"list-group\" id=\"status-list\">\r\n\t\t\t\t  <li class=\"list-group-item\">\r\n\t\t\t\t    <span class=\"badge\" id=\"status-status\"></span>\r\n\t\t\t\t    Status\r\n\t\t\t\t  </li>\r\n\t\t\t\t  <li class=\"list-group-item\">\r\n\t\t\t\t    <span class=\"badge\" id=\"status-ssid\"></span>\r\n\t\t\t\t    SSID\r\n\t\t\t\t  </li>\r\n\t\t\t\t  <li class=\"list-group-item\">\r\n\t\t\t\t    <span class=\"badge\"  id=\"status-ip\"></span>\r\n\t\t\t\t    IP\r\n\t\t\t\t  </li>\r\n\t\t\t\t   <li class=\"list-group-item\">\r\n\t\t\t\t    <span class=\"badge\"  id=\"status-internet\"></span>\r\n\t\t\t\t    Internet?\r\n\t\t\t\t  </li>\r\n\t\t\t</ul>\r\n\t\t\t<p class=\"bs-component\">                \t\r\n                \t<a href=\"#\" class=\"btn btn-info\" id=\"btn-disconnect\" style=\"display:none\">Disconnect</a>\r\n        \t\t</p>\r\n        </div>      \r\n\r\n        <div id=\"network-scan\">\r\n        \t<div class=\"page-header\">\r\n\t\t\t\t<h3>Available networks</h3>\r\n\t\t\t</div>\r\n\r\n        \t<div id=\"scan-progress\">\r\n            \t<h3>Wait while we scan for wifi networks...</h3>\r\n                <div class=\"progress progress-striped active\"  width=\"50%\">\r\n\t\t\t\t  \t<div class=\"progress-bar\" style=\"width: 100%\"></div>\r\n\t\t\t\t</div>   \r\n        \t</div>\r\n                    \r\n            <div id=\"scan-result\" style=\"display:none\">                \t\r\n            \t<div id=\"scan-result-empty\">\r\n            \t\t<h3>No network found :(</h3>\r\n            \t</div>\r\n\r\n            \t<table class=\"table table-striped table-hover\" id=\"scan-result-table\">\r\n\t\t\t\t  <thead>\r\n\t\t\t\t    <tr class=\"success\">\r\n\t\t\t\t      <th>Network</th>\r\n\t\t\t\t      <!--<th class=\"text-center\">Channel</th>-->\r\n\t\t\t\t      <th class=\"text-center\">Encryption</th>\r\n\t\t\t\t      <th class=\"text-center\">Signal</th>\t\t\t\t\t      \r\n\t\t\t\t    </tr>\r\n\t\t\t\t  </thead>\r\n\t\t\t\t  <tbody>\t\t\t\t\t   \r\n\t\t\t\t  </tbody>\r\n\t\t\t\t</table> \r\n\t\t\t\t<p class=\"bs-component\">                \t\r\n                \t<a href=\"#\" class=\"btn btn-info\" id=\"btn-scan\">Scan again</a>\r\n        \t\t</p>\r\n            </div>\r\n        </div>\r\n\r\n         <div style=\"margin-bottom:30px\">\r\n\t\t\t<div class=\"page-header\">\r\n\t\t\t\t\t<h2>Your sensor</h2>\r\n\t\t\t</div>\r\n\t\t\t<div >\r\n\t\t\t \t <canvas id=\"sensor-chart\" height=\"250\"></canvas>\r\n\t\t\t</div>\r\n\t\t\t<div>\r\n\t\t\t\t<span>Temperature: </span><span id=\"temp-data\">0 C</span>\t\r\n\t\t\t\t<br/>\t\r\n\t\t\t\t<span>Humidity: </span><span id=\"hum-data\">0 %</span>\r\n\t\t\t</div>\r\n\t\t\t\t\r\n\r\n\t\t</div>\r\n\r\n        <div id=\"relay-test\" style=\"margin-bottom:30px\">\r\n\t\t\t<div class=\"page-header\">\r\n\t\t\t\t\t<h2>Test your relay</h2>\r\n\t\t\t</div>\r\n\r\n\t\t\t<a href=\"#\" class=\"btn btn-default relay-button\" data-relay=\"0\" id=\"relay-button-0\">Relay #0 OFF</a>\r\n\t\t\t<a href=\"#\" class=\"btn btn-default relay-button\" data-relay=\"1\" id=\"relay-button-1\">Relay #1 OFF</a>\t\t\r\n\r\n\t\t</div>\r\n        \r\n\t</div>\r\n\r\n\t\r\n\t\r\n\r\n\t<div class=\"modal\" id=\"connect-modal\" >\r\n\t  <div class=\"modal-dialog\">\r\n\r\n\t    <div class=\"modal-content connect\">\r\n\t      <div class=\"modal-header\">\r\n\t        \r\n\t        <h4 class=\"modal-title\" id=\"modal-connect-title\"></h4>\r\n\t      </div>\r\n\t      <div class=\"modal-body\">\r\n\t        <div class=\"form-group\" id=\"modal-connect-password\">\r\n\t\t\t  <label class=\"control-label\" for=\"modal-connect-password-input\">Password</label>\r\n\t\t\t  <input class=\"form-control\" id=\"modal-connect-password-input\" type=\"text\" value=\"\" placeholder=\"Write your wifi password\">\r\n\t\t\t</div>\r\n\t\t\t<div id=\"modal-connect-no-password\">\r\n\t\t\t\t<p>This is an open network</p>\r\n\t\t\t</div> \r\n\t      </div>\r\n\t      <div class=\"modal-footer\">\r\n\t        <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\" id=\"modal-connect-button-close\">Close</button>\r\n\t        <button type=\"button\" class=\"btn btn-primary\" id=\"modal-connect-button-connect\">Connect</button>\r\n\t      </div>\r\n\t    </div>\r\n\r\n\t    <div class=\"modal-content connecting\" style=\"display:none\">  \r\n\t      <div class=\"modal-header\">\t        \r\n\t        <h4 class=\"modal-title\">Connecting...</h4>\r\n\t      </div>\r\n\t      <div class=\"modal-body\">\r\n\t        <div class=\"progress progress-striped active\"  width=\"50%\">\r\n\t\t\t  \t<div class=\"progress-bar\" style=\"width: 100%\"></div>\r\n\t\t\t</div>\t\t\t\r\n\t      </div>\r\n\t      <div class=\"modal-footer\">\t        \r\n\t      </div>\r\n\t    </div>\r\n\r\n\t    <div class=\"modal-content success\" style=\"display:none\">  \r\n\t      <div class=\"modal-header\">\t        \r\n\t        <h4 class=\"modal-title\">Success!</h4>\r\n\t      </div>\r\n\t      <div class=\"modal-body\">\r\n    \t\t<h3> </h3>\r\n\t      </div>\r\n\t      <div class=\"modal-footer\">\r\n\t       <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\" id=\"modal-connect-button-close\">Close</button>\t        \r\n\t      </div>\r\n\t    </div>\r\n\r\n\t  </div>\r\n\t</div>\r\n\r\n\t<script src=\"lib.js\" type=\"text/javascript\"></script>\r\n\t<script src=\"index.js\" type=\"text/javascript\"></script>\r\n\r\n  </body>\r\n </html>"
  },
  {
    "path": "app/http/html/index.js",
    "content": "$(function(){\r\n\r\n\tvar scanning = 0;\r\n\t\r\n\tvar scanResult=null;\r\n\r\n\tfunction wifiConnectModal(id){\r\n\r\n\t\tif(scanResult==null)\r\n\t\t\treturn;\r\n\r\n\t\tvar modal = $('#connect-modal');\r\n\t\tvar ap = scanResult.ap[id];\r\n\r\n\t\tmodal.find('#modal-connect-title').text('Connect to '+ap.ssid);\r\n\t\tif(ap.enc==0){\r\n\t\t\tmodal.find('#modal-connect-password').hide();\r\n\t\t\tmodal.find('#modal-connect-no-password').show();\r\n\t\t}\r\n\t\telse{\r\n\t\t\tmodal.find('#modal-connect-password').show();\r\n\t\t\tmodal.find('#modal-connect-no-password').hide();\r\n\r\n\t\t\tmodal.find('#modal-connect-password-input').val('');\r\n\t\t}\r\n\r\n\t\tmodal.data('ap',ap);\r\n\r\n\t\t$('#connect-modal .modal-content.connect').show();\r\n\t\t$('#connect-modal .modal-content.success').hide();\r\n\t\t$('#connect-modal .modal-content.connecting').hide();\r\n\t\t\r\n\t\tmodal.modal({show:true,backdrop:false});\r\n\r\n\t\t$('#modal-connect-password-input').focus();\r\n\t}\r\n\r\n\tfunction wifiScan(){\r\n\r\n\t\tscanning=1;\r\n\t\t//hide result, show progress\r\n\t\t$('#scan-result').hide();\r\n\t\t$('#scan-progress').show();\r\n\r\n\t\t$.ajax(\r\n\t\t \t{\r\n\t\t\t\ttype:'POST',\r\n\t\t\t\turl:'/api/wifi/scan',\r\n\t\t\t\tdata:null,\t\t\t\t\r\n\t\t\t\tsuccess: function(data){\r\n\r\n\t\t\t\t\tscanning=0;\r\n\r\n\t\t\t\t\tscanResult = data;\r\n\r\n\t\t\t\t\t//hide progress, show result\r\n\t\t\t\t\t$('#scan-result').show();\r\n\t\t\t\t\t$('#scan-progress').hide();\r\n\r\n\t\t\t\t\tif(data.ap_count==0){\r\n\t\t\t\t\t\t$('#scan-result-empty').show();\r\n\t\t\t\t\t\t$('#scan-result-table').hide();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse{\r\n\r\n\t\t\t\t\t\t$('#scan-result-empty').hide();\r\n\t\t\t\t\t\t$('#scan-result-table').show();\r\n\r\n\t\t\t\t\t\t$('#scan-result tbody tr').remove(); //empty table\r\n\r\n\t\t\t\t\t\t//sort \r\n\t\t\t\t\t\tdata.ap = data.ap.sort(function(a,b){return b.rssi - a.rssi });\r\n\r\n\t\t\t\t\t\tfor(i=0;i<data.ap_count;i++){\r\n\t\t\t       \t\t\t\r\n\t\t\t       \t\t\tvar ap = data.ap[i];\r\n\t\t\t       \t\t\tvar tr = $('<tr>');\r\n\t\t\t       \t\t\ttr.data('ap-id',i);\r\n\t\t\t\t          \t\r\n\t\t\t\t          \tvar td_name = $('<td>');\r\n\t\t\t\t          \ttd_name.text(ap.ssid);\r\n\t\t\t\t          \ttd_name.appendTo(tr);\r\n\r\n\t\t\t\t          \tvar td_channel = $('<td class=\"text-center\">');\r\n\t\t\t\t          \ttd_channel.text(ap.channel);\r\n\t\t\t\t          \t//td_channel.appendTo(tr);\r\n\r\n\t\t\t\t          \tvar td_enc = $('<td class=\"text-center\">')\r\n\t\t\t\t          \ttr.data('enc',ap.enc);\r\n\t\t\t\t          \tswitch(ap.enc){\r\n\t\t\t\t          \t\tcase 0:\r\n\t\t\t\t          \t\t\ttd_enc.text(\"OPEN\");\r\n\t\t\t\t          \t\t\tbreak;\r\n\t\t\t\t          \t\tcase 1:\r\n\t\t\t\t          \t\t\ttd_enc.text(\"CLOSED\");\r\n\t\t\t\t          \t\t\tbreak;\r\n\t\t\t\t          \t\tcase 2:\r\n\t\t\t\t          \t\t\ttd_enc.text(\"CLOSED\");\r\n\t\t\t\t          \t\t\tbreak;\r\n\t\t\t\t          \t\tcase 3:\r\n\t\t\t\t          \t\t\ttd_enc.text(\"CLOSED\");\r\n\t\t\t\t          \t\t\tbreak;\r\n\t\t\t\t          \t\tcase 4:\r\n\t\t\t\t          \t\t\ttd_enc.text(\"CLOSED\");\r\n\t\t\t\t          \t\t\tbreak;\r\n\t\t\t\t          \t\tdefault:\r\n\t\t\t\t          \t\t\ttd_enc.text(\"CLOSED\");\r\n\t\t\t\t          \t\t\tbreak;\r\n\t\t\t\t          \t}\r\n\t\t\t\t          \ttd_enc.appendTo(tr);\r\n\r\n\t\t\t\t          \tvar td_signal = $('<td  class=\"text-center\">');\r\n\t\t\t\t          \tvar signal_pct = 100*ap.rssi/256.0;\r\n\t\t\t\t          \tvar signal_span = $('<span class=\"label\"></span>');\r\n\t\t\t\t          \tsignal_span.text(signal_pct.toFixed('f2')+'%');\r\n\r\n\t\t\t\t          \tif(signal_pct > 70) signal_span.addClass('label-success');\r\n\t\t\t\t          \telse if(signal_pct > 40) signal_span.addClass('label-warning');\r\n\t\t\t\t          \telse signal_pct.addClass('label-danger');\r\n\r\n\t\t\t\t          \tsignal_span.appendTo(td_signal);\r\n\t\t\t\t          \ttd_signal.appendTo(tr);\r\n\r\n\t\t\t\t          \ttr.appendTo($('#scan-result tbody').first());\r\n\r\n\t\t\t\t           \t\r\n\t\t\t\t        }\r\n\t\t\t\t    }\r\n\t\t\t\t},\r\n\t\t\t\tfail:function(){\r\n\r\n\t\t\t\t\tscanning=0;\r\n\t\t\t\t\t//hide progress, show result\r\n\t\t\t\t\t$('#scan-result').show();\r\n\t\t\t\t\t$('#scan-progress').hide();\r\n\r\n\t\t\t\t\t$('#scan-result-empty').show();\r\n\t\t\t\t\t$('#scan-result-table').hide();\r\n\r\n\t\t\t\t}\r\n\t\t\t});\t\t\t\r\n\t}\r\n\r\n\tfunction wifiConnect(ssid,pwd){\r\n\r\n\t\tvar postData = {\"ssid\":ssid,\"pwd\":pwd};\r\n\r\n\t\t$('#connect-modal .modal-content.connect').hide();\r\n\t\t$('#connect-modal .modal-content.success').hide();\r\n\t\t$('#connect-modal .modal-content.connecting').show();\r\n\r\n\t\t$.ajax(\r\n\t\t \t{\r\n\t\t\t\ttype:'POST',\r\n\t\t\t\turl:'/api/wifi/connect',\r\n\t\t\t\tdata:JSON.stringify(postData),\r\n\t\t\t\tcontentType: 'application/json',\r\n\t\t\t\tsuccess:function(data){\r\n\r\n\t\t\t\t\t$('#connect-modal .modal-content.connect').hide();\r\n\t\t\t\t\t$('#connect-modal .modal-content.success').show();\r\n\t\t\t\t\t$('#connect-modal .modal-content.connecting').hide();\r\n\r\n\t\t\t\t\t$('#connect-modal .modal-content.success h3')\r\n\t\t\t\t\t\t.text('Relay now connected to '+ssid+' with ip: '+data.ip);\r\n\t\t\t\t\t\t\r\n\t\t\t\t\twifiStatus();\r\n\r\n\t\t\t\t},\r\n\t\t\t\tfail:function(){\r\n\r\n\t\t\t\t\t$('#connect-modal .modal-content.connect').show();\r\n\t\t\t\t\t$('#connect-modal .modal-content.success').hide();\r\n\t\t\t\t\t$('#connect-modal .modal-content.connecting').hide();\r\n\t\t\t\t\twifiStatus();\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t}\r\n\r\n\tfunction checkInternet(){\r\n\r\n\t\tvar status_internet=$('#status-internet');\r\n\t\tstatus_internet.text(\"Checking...\");\r\n\r\n\t\t$.ajax(\r\n\t\t \t{\r\n\t\t\t\ttype:'POST',\r\n\t\t\t\turl:'/api/wifi/checkInternet',\r\n\t\t\t\tdata:'',\r\n\t\t\t\tcontentType: 'application/json',\r\n\t\t\t\tsuccess:function(data){\r\n\r\n\t\t\t\t\tif(data.status==1){\r\n\t\t\t\t\t\tstatus_internet.text(\"YES!\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse{\r\n\t\t\t\t\t\tstatus_internet.text(\"NO :(\");\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t}\r\n\r\n\tfunction wifiStatus(){\r\n\r\n\t\t$.ajax(\r\n\t\t \t{\r\n\t\t\t\ttype:'POST',\r\n\t\t\t\turl:'/api/wifi/status',\r\n\t\t\t\tdata:'',\r\n\t\t\t\tcontentType: 'application/json',\r\n\t\t\t\tsuccess:function(data){\r\n\r\n\t\t\t\t\tvar status_status=$('#status-status');\r\n\t\t\t\t\tvar status_ip = $('#status-ip');\r\n\t\t\t\t\tvar status_ssid = $('#status-ssid');\r\n\t\t\t\t\tswitch(data.station_status){\r\n\t\t\t\t\t \tcase 5:\r\n\t\t\t\t\t \t\tstatus_status.text('Connected');\t\t\t\t\t \t\t\r\n\t\t\t\t\t \t\tbreak;\r\n\t\t\t\t\t \tcase 4:\r\n\t\t\t\t\t \t\tstatus_status.text('Fail');\r\n\t\t\t\t\t \t\tbreak;\r\n\t\t\t\t \t\tcase 3:\r\n\t\t\t\t\t \t\tstatus_status.text('Ap Not Found');\r\n\t\t\t\t\t \t\tbreak;\r\n\t\t\t\t\t \tcase 2:\r\n\t\t\t\t\t \t\tstatus_status.text('Wrong Password');\r\n\t\t\t\t\t \t\tbreak;\r\n\t\t\t\t\t \tcase 1:\r\n\t\t\t\t\t \t\tstatus_status.text('Connecting');\r\n\t\t\t\t\t \t\tbreak;\r\n\t\t\t\t\t \tcase 0:\r\n\t\t\t\t\t \t\tstatus_status.text('Not Configured');\r\n\t\t\t\t\t \t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tstatus_ssid.text(data.ssid);\t\r\n\t\t\t\t\tstatus_ip.text(data.ip);\r\n\r\n\t\t\t\t\tif(data.station_status==5){\r\n\r\n\t\t\t\t\t\t$('#btn-disconnect').show();\r\n\t\t\t\t\t\t$('#network-scan').hide();\r\n\t\t\t\t\t\tcheckInternet();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse{\r\n\t\t\t\t\t\twifiScan();\r\n\t\t\t\t\t\t$('#network-scan').show();\r\n\t\t\t\t\t\t$('#btn-disconnect').hide();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t}\r\n\r\n\tfunction wifiDisconnect(){\r\n\r\n\t\t$.ajax(\r\n\t\t \t{\r\n\t\t\t\ttype:'POST',\r\n\t\t\t\turl:'/api/wifi/disconnect',\r\n\t\t\t\tdata:'',\r\n\t\t\t\tcontentType: 'application/json',\r\n\t\t\t\tsuccess:function(data){\r\n\r\n\t\t\t\t\twifiStatus();\r\n\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\tvar status_internet=$('#status-internet');\r\n\t\tstatus_internet.text(\"\");\r\n\r\n\t}\r\n\r\n\tfunction relayQueryStatus(){\r\n\r\n\t\t$.ajax(\r\n\t\t \t{\r\n\t\t\t\ttype:'POST',\r\n\t\t\t\turl:'/api/relay/state',\r\n\t\t\t\tdata:'',\r\n\t\t\t\tcontentType: 'application/json',\r\n\t\t\t\tsuccess:function(data){\r\n\r\n\t\t\t\t\t$.each(data.relays,function(index,item){\r\n\r\n\t\t\t\t\t\tvar btn = $('#relay-button-'+item.relay);\r\n\r\n\t\t\t\t\t\trelayStatus(item.relay,item.state);\r\n\r\n\t\t\t\t\t});\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t}\r\n\r\n\tfunction relayStatus(id,status){\r\n\r\n\t\tvar btn = $('#relay-button-'+id);\r\n\r\n\t\tif(status==0){\r\n\t\t\tbtn.text('Relay #'+id+' OFF');\r\n\t\t\tbtn.removeClass('btn-success');\r\n\t\t\tbtn.addClass('btn-default');\r\n\t\t}\r\n\t\telse{\r\n\t\t\tbtn.text('Relay #'+id+' ON');\r\n\t\t\tbtn.removeClass('btn-default');\r\n\t\t\tbtn.addClass('btn-success');\r\n\t\t\t\r\n\t\t}\r\n\t}\r\n\r\n\tfunction relayToggle(id){\r\n\r\n\t\tvar data = {'relay':id}\r\n\t\t$.ajax(\r\n\t\t \t{\r\n\t\t\t\ttype:'POST',\r\n\t\t\t\turl:'/api/relay/toggle',\r\n\t\t\t\tdata:JSON.stringify(data),\r\n\t\t\t\tcontentType: 'application/json',\r\n\t\t\t\tsuccess:function(data){\r\n\r\n\t\t\t\t\trelayStatus(id,data.state);\r\n\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t}\r\n\t//sensor\r\n\tvar canvas = $('#sensor-chart');\r\n\tcanvas.attr('width',canvas.parent().width());\r\n\tvar ctx = document.getElementById(\"sensor-chart\").getContext(\"2d\");\t\t\t\r\n\tvar options = {animation :false} ;\r\n\tvar chartData = {\r\n\t\t    labels: [],\r\n\t\t    datasets: [\r\n\t\t\t\t        {\r\n\t\t\t\t            label: \"Temperature\",\r\n\t\t\t\t            fillColor: \"rgba(220,220,220,0.2)\",\r\n\t\t\t\t            strokeColor: \"rgba(220,220,220,1)\",\r\n\t\t\t\t            pointColor: \"rgba(220,220,220,1)\",\r\n\t\t\t\t            pointStrokeColor: \"#fff\",\r\n\t\t\t\t            pointHighlightFill: \"#fff\",\r\n\t\t\t\t            pointHighlightStroke: \"rgba(220,220,220,1)\",\r\n\t\t\t\t            data: []\r\n\t\t\t\t        },\r\n\t\t\t\t        {\r\n\t\t\t\t            label: \"Humidity\",\r\n\t\t\t\t            fillColor: \"rgba(151,187,205,0.2)\",\r\n\t\t\t\t            strokeColor: \"rgba(151,187,205,1)\",\r\n\t\t\t\t            pointColor: \"rgba(151,187,205,1)\",\r\n\t\t\t\t            pointStrokeColor: \"#fff\",\r\n\t\t\t\t            pointHighlightFill: \"#fff\",\r\n\t\t\t\t            pointHighlightStroke: \"rgba(151,187,205,1)\",\r\n\t\t\t\t            data: []\r\n\t\t\t\t        }\r\n\t\t    \t\t]\r\n\t\t\t};\r\n\r\n\t//init data\t\t\t\r\n\r\n\tvar lineChart = new Chart(ctx).Line(chartData, options);\r\n\r\n\tfunction sensorRead(){\r\n\r\n\t\t$.ajax(\r\n\t\t \t{\r\n\t\t\t\ttype:'POST',\r\n\t\t\t\turl:'/api/dht/read',\r\n\t\t\t\tdata:'',\r\n\t\t\t\tcontentType: 'application/json',\r\n\t\t\t\tsuccess:function(data){\r\n\r\n\t\t\t\t\t$('#temp-data').text(data.temp.toFixed(2)+' C');\r\n\t\t\t\t\t$('#hum-data').text(data.hum.toFixed(2)+' %');\r\n\t\t\t\t\t//chart push new\r\n\t\t\t        lineChart.addData([data.temp,data.hum],'');\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t}\t\r\n\tsetInterval(sensorRead,5000); //read every 5s\r\n\t\r\n\r\n\t$('#btn-scan').on('click',function(e){\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tif(!scanning)\r\n\t\t\twifiScan();\r\n\t});\r\n\r\n\t$('#btn-disconnect').on('click',function(e){\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\twifiDisconnect();\r\n\t});\r\n\t\r\n\t$(document).on('click','#scan-result tbody tr',function(e){\r\n\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tvar id = $(e.currentTarget).data('ap-id');\r\n\t\twifiConnectModal(id);\r\n\r\n\t});\r\n\r\n\t$('a.relay-button').on('click',function(e){\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\t\tvar id = $(this).data('relay');\r\n\t\trelayToggle(id);\r\n\t});\r\n\r\n\t$(document).on('click','#modal-connect-button-connect',function(e){\r\n\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tvar modal = $('#connect-modal');\r\n\t\tvar ap = modal.data('ap');\r\n\r\n\t\tvar pwd = modal.find('#modal-connect-password-input').val();\r\n\r\n\t\twifiConnect(ap.ssid,pwd);\r\n\r\n\t});\t\t\r\n\r\n\twifiStatus();\r\n\trelayQueryStatus();\r\n\r\n});\r\n\r\n\t\t"
  },
  {
    "path": "app/http/html/lib.js",
    "content": "//ZEPTO\nvar Zepto=function(){function F(a){return null==a?String(a):x[y.call(a)]||\"object\"}function G(a){return\"function\"==F(a)}function H(a){return null!=a&&a==a.window}function I(a){return null!=a&&a.nodeType==a.DOCUMENT_NODE}function J(a){return\"object\"==F(a)}function K(a){return J(a)&&!H(a)&&Object.getPrototypeOf(a)==Object.prototype}function L(a){return\"number\"==typeof a.length}function M(a){return g.call(a,function(a){return null!=a})}function N(a){return a.length>0?c.fn.concat.apply([],a):a}function O(a){return a.replace(/::/g,\"/\").replace(/([A-Z]+)([A-Z][a-z])/g,\"$1_$2\").replace(/([a-z\\d])([A-Z])/g,\"$1_$2\").replace(/_/g,\"-\").toLowerCase()}function P(a){return a in j?j[a]:j[a]=new RegExp(\"(^|\\\\s)\"+a+\"(\\\\s|$)\")}function Q(a,b){return\"number\"!=typeof b||k[O(a)]?b:b+\"px\"}function R(a){var b,c;return i[a]||(b=h.createElement(a),h.body.appendChild(b),c=getComputedStyle(b,\"\").getPropertyValue(\"display\"),b.parentNode.removeChild(b),\"none\"==c&&(c=\"block\"),i[a]=c),i[a]}function S(a){return\"children\"in a?f.call(a.children):c.map(a.childNodes,function(a){return 1==a.nodeType?a:void 0})}function T(c,d,e){for(b in d)e&&(K(d[b])||E(d[b]))?(K(d[b])&&!K(c[b])&&(c[b]={}),E(d[b])&&!E(c[b])&&(c[b]=[]),T(c[b],d[b],e)):d[b]!==a&&(c[b]=d[b])}function U(a,b){return null==b?c(a):c(a).filter(b)}function V(a,b,c,d){return G(b)?b.call(a,c,d):b}function W(a,b,c){null==c?a.removeAttribute(b):a.setAttribute(b,c)}function X(b,c){var d=b.className||\"\",e=d&&d.baseVal!==a;return c===a?e?d.baseVal:d:(e?d.baseVal=c:b.className=c,void 0)}function Y(a){try{return a?\"true\"==a||(\"false\"==a?!1:\"null\"==a?null:+a+\"\"==a?+a:/^[\\[\\{]/.test(a)?c.parseJSON(a):a):a}catch(b){return a}}function Z(a,b){b(a);for(var c=0,d=a.childNodes.length;d>c;c++)Z(a.childNodes[c],b)}var a,b,c,d,A,B,e=[],f=e.slice,g=e.filter,h=window.document,i={},j={},k={\"column-count\":1,columns:1,\"font-weight\":1,\"line-height\":1,opacity:1,\"z-index\":1,zoom:1},l=/^\\s*<(\\w+|!)[^>]*>/,m=/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,n=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,o=/^(?:body|html)$/i,p=/([A-Z])/g,q=[\"val\",\"css\",\"html\",\"text\",\"data\",\"width\",\"height\",\"offset\"],r=[\"after\",\"prepend\",\"before\",\"append\"],s=h.createElement(\"table\"),t=h.createElement(\"tr\"),u={tr:h.createElement(\"tbody\"),tbody:s,thead:s,tfoot:s,td:t,th:t,\"*\":h.createElement(\"div\")},v=/complete|loaded|interactive/,w=/^[\\w-]*$/,x={},y=x.toString,z={},C=h.createElement(\"div\"),D={tabindex:\"tabIndex\",readonly:\"readOnly\",\"for\":\"htmlFor\",\"class\":\"className\",maxlength:\"maxLength\",cellspacing:\"cellSpacing\",cellpadding:\"cellPadding\",rowspan:\"rowSpan\",colspan:\"colSpan\",usemap:\"useMap\",frameborder:\"frameBorder\",contenteditable:\"contentEditable\"},E=Array.isArray||function(a){return a instanceof Array};return z.matches=function(a,b){if(!b||!a||1!==a.nodeType)return!1;var c=a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.matchesSelector;if(c)return c.call(a,b);var d,e=a.parentNode,f=!e;return f&&(e=C).appendChild(a),d=~z.qsa(e,b).indexOf(a),f&&C.removeChild(a),d},A=function(a){return a.replace(/-+(.)?/g,function(a,b){return b?b.toUpperCase():\"\"})},B=function(a){return g.call(a,function(b,c){return a.indexOf(b)==c})},z.fragment=function(b,d,e){var g,i,j;return m.test(b)&&(g=c(h.createElement(RegExp.$1))),g||(b.replace&&(b=b.replace(n,\"<$1></$2>\")),d===a&&(d=l.test(b)&&RegExp.$1),d in u||(d=\"*\"),j=u[d],j.innerHTML=\"\"+b,g=c.each(f.call(j.childNodes),function(){j.removeChild(this)})),K(e)&&(i=c(g),c.each(e,function(a,b){q.indexOf(a)>-1?i[a](b):i.attr(a,b)})),g},z.Z=function(a,b){return a=a||[],a.__proto__=c.fn,a.selector=b||\"\",a},z.isZ=function(a){return a instanceof z.Z},z.init=function(b,d){var e;if(!b)return z.Z();if(\"string\"==typeof b)if(b=b.trim(),\"<\"==b[0]&&l.test(b))e=z.fragment(b,RegExp.$1,d),b=null;else{if(d!==a)return c(d).find(b);e=z.qsa(h,b)}else{if(G(b))return c(h).ready(b);if(z.isZ(b))return b;if(E(b))e=M(b);else if(J(b))e=[b],b=null;else if(l.test(b))e=z.fragment(b.trim(),RegExp.$1,d),b=null;else{if(d!==a)return c(d).find(b);e=z.qsa(h,b)}}return z.Z(e,b)},c=function(a,b){return z.init(a,b)},c.extend=function(a){var b,c=f.call(arguments,1);return\"boolean\"==typeof a&&(b=a,a=c.shift()),c.forEach(function(c){T(a,c,b)}),a},z.qsa=function(a,b){var c,d=\"#\"==b[0],e=!d&&\".\"==b[0],g=d||e?b.slice(1):b,h=w.test(g);return I(a)&&h&&d?(c=a.getElementById(g))?[c]:[]:1!==a.nodeType&&9!==a.nodeType?[]:f.call(h&&!d?e?a.getElementsByClassName(g):a.getElementsByTagName(b):a.querySelectorAll(b))},c.contains=h.documentElement.contains?function(a,b){return a!==b&&a.contains(b)}:function(a,b){for(;b&&(b=b.parentNode);)if(b===a)return!0;return!1},c.type=F,c.isFunction=G,c.isWindow=H,c.isArray=E,c.isPlainObject=K,c.isEmptyObject=function(a){var b;for(b in a)return!1;return!0},c.inArray=function(a,b,c){return e.indexOf.call(b,a,c)},c.camelCase=A,c.trim=function(a){return null==a?\"\":String.prototype.trim.call(a)},c.uuid=0,c.support={},c.expr={},c.map=function(a,b){var c,e,f,d=[];if(L(a))for(e=0;e<a.length;e++)c=b(a[e],e),null!=c&&d.push(c);else for(f in a)c=b(a[f],f),null!=c&&d.push(c);return N(d)},c.each=function(a,b){var c,d;if(L(a)){for(c=0;c<a.length;c++)if(b.call(a[c],c,a[c])===!1)return a}else for(d in a)if(b.call(a[d],d,a[d])===!1)return a;return a},c.grep=function(a,b){return g.call(a,b)},window.JSON&&(c.parseJSON=JSON.parse),c.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"),function(a,b){x[\"[object \"+b+\"]\"]=b.toLowerCase()}),c.fn={forEach:e.forEach,reduce:e.reduce,push:e.push,sort:e.sort,indexOf:e.indexOf,concat:e.concat,map:function(a){return c(c.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return c(f.apply(this,arguments))},ready:function(a){return v.test(h.readyState)&&h.body?a(c):h.addEventListener(\"DOMContentLoaded\",function(){a(c)},!1),this},get:function(b){return b===a?f.call(this):this[b>=0?b:b+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(a){return e.every.call(this,function(b,c){return a.call(b,c,b)!==!1}),this},filter:function(a){return G(a)?this.not(this.not(a)):c(g.call(this,function(b){return z.matches(b,a)}))},add:function(a,b){return c(B(this.concat(c(a,b))))},is:function(a){return this.length>0&&z.matches(this[0],a)},not:function(b){var d=[];if(G(b)&&b.call!==a)this.each(function(a){b.call(this,a)||d.push(this)});else{var e=\"string\"==typeof b?this.filter(b):L(b)&&G(b.item)?f.call(b):c(b);this.forEach(function(a){e.indexOf(a)<0&&d.push(a)})}return c(d)},has:function(a){return this.filter(function(){return J(a)?c.contains(this,a):c(this).find(a).size()})},eq:function(a){return-1===a?this.slice(a):this.slice(a,+a+1)},first:function(){var a=this[0];return a&&!J(a)?a:c(a)},last:function(){var a=this[this.length-1];return a&&!J(a)?a:c(a)},find:function(a){var b,d=this;return b=a?\"object\"==typeof a?c(a).filter(function(){var a=this;return e.some.call(d,function(b){return c.contains(b,a)})}):1==this.length?c(z.qsa(this[0],a)):this.map(function(){return z.qsa(this,a)}):c()},closest:function(a,b){var d=this[0],e=!1;for(\"object\"==typeof a&&(e=c(a));d&&!(e?e.indexOf(d)>=0:z.matches(d,a));)d=d!==b&&!I(d)&&d.parentNode;return c(d)},parents:function(a){for(var b=[],d=this;d.length>0;)d=c.map(d,function(a){return(a=a.parentNode)&&!I(a)&&b.indexOf(a)<0?(b.push(a),a):void 0});return U(b,a)},parent:function(a){return U(B(this.pluck(\"parentNode\")),a)},children:function(a){return U(this.map(function(){return S(this)}),a)},contents:function(){return this.map(function(){return f.call(this.childNodes)})},siblings:function(a){return U(this.map(function(a,b){return g.call(S(b.parentNode),function(a){return a!==b})}),a)},empty:function(){return this.each(function(){this.innerHTML=\"\"})},pluck:function(a){return c.map(this,function(b){return b[a]})},show:function(){return this.each(function(){\"none\"==this.style.display&&(this.style.display=\"\"),\"none\"==getComputedStyle(this,\"\").getPropertyValue(\"display\")&&(this.style.display=R(this.nodeName))})},replaceWith:function(a){return this.before(a).remove()},wrap:function(a){var b=G(a);if(this[0]&&!b)var d=c(a).get(0),e=d.parentNode||this.length>1;return this.each(function(f){c(this).wrapAll(b?a.call(this,f):e?d.cloneNode(!0):d)})},wrapAll:function(a){if(this[0]){c(this[0]).before(a=c(a));for(var b;(b=a.children()).length;)a=b.first();c(a).append(this)}return this},wrapInner:function(a){var b=G(a);return this.each(function(d){var e=c(this),f=e.contents(),g=b?a.call(this,d):a;f.length?f.wrapAll(g):e.append(g)})},unwrap:function(){return this.parent().each(function(){c(this).replaceWith(c(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css(\"display\",\"none\")},toggle:function(b){return this.each(function(){var d=c(this);(b===a?\"none\"==d.css(\"display\"):b)?d.show():d.hide()})},prev:function(a){return c(this.pluck(\"previousElementSibling\")).filter(a||\"*\")},next:function(a){return c(this.pluck(\"nextElementSibling\")).filter(a||\"*\")},html:function(a){return 0 in arguments?this.each(function(b){var d=this.innerHTML;c(this).empty().append(V(this,a,b,d))}):0 in this?this[0].innerHTML:null},text:function(a){return 0 in arguments?this.each(function(b){var c=V(this,a,b,this.textContent);this.textContent=null==c?\"\":\"\"+c}):0 in this?this[0].textContent:null},attr:function(c,d){var e;return\"string\"!=typeof c||1 in arguments?this.each(function(a){if(1===this.nodeType)if(J(c))for(b in c)W(this,b,c[b]);else W(this,c,V(this,d,a,this.getAttribute(c)))}):this.length&&1===this[0].nodeType?!(e=this[0].getAttribute(c))&&c in this[0]?this[0][c]:e:a},removeAttr:function(a){return this.each(function(){1===this.nodeType&&a.split(\" \").forEach(function(a){W(this,a)},this)})},prop:function(a,b){return a=D[a]||a,1 in arguments?this.each(function(c){this[a]=V(this,b,c,this[a])}):this[0]&&this[0][a]},data:function(b,c){var d=\"data-\"+b.replace(p,\"-$1\").toLowerCase(),e=1 in arguments?this.attr(d,c):this.attr(d);return null!==e?Y(e):a},val:function(a){return 0 in arguments?this.each(function(b){this.value=V(this,a,b,this.value)}):this[0]&&(this[0].multiple?c(this[0]).find(\"option\").filter(function(){return this.selected}).pluck(\"value\"):this[0].value)},offset:function(a){if(a)return this.each(function(b){var d=c(this),e=V(this,a,b,d.offset()),f=d.offsetParent().offset(),g={top:e.top-f.top,left:e.left-f.left};\"static\"==d.css(\"position\")&&(g.position=\"relative\"),d.css(g)});if(!this.length)return null;var b=this[0].getBoundingClientRect();return{left:b.left+window.pageXOffset,top:b.top+window.pageYOffset,width:Math.round(b.width),height:Math.round(b.height)}},css:function(a,d){if(arguments.length<2){var e,f=this[0];if(!f)return;if(e=getComputedStyle(f,\"\"),\"string\"==typeof a)return f.style[A(a)]||e.getPropertyValue(a);if(E(a)){var g={};return c.each(a,function(a,b){g[b]=f.style[A(b)]||e.getPropertyValue(b)}),g}}var h=\"\";if(\"string\"==F(a))d||0===d?h=O(a)+\":\"+Q(a,d):this.each(function(){this.style.removeProperty(O(a))});else for(b in a)a[b]||0===a[b]?h+=O(b)+\":\"+Q(b,a[b])+\";\":this.each(function(){this.style.removeProperty(O(b))});return this.each(function(){this.style.cssText+=\";\"+h})},index:function(a){return a?this.indexOf(c(a)[0]):this.parent().children().indexOf(this[0])},hasClass:function(a){return a?e.some.call(this,function(a){return this.test(X(a))},P(a)):!1},addClass:function(a){return a?this.each(function(b){if(\"className\"in this){d=[];var e=X(this),f=V(this,a,b,e);f.split(/\\s+/g).forEach(function(a){c(this).hasClass(a)||d.push(a)},this),d.length&&X(this,e+(e?\" \":\"\")+d.join(\" \"))}}):this},removeClass:function(b){return this.each(function(c){if(\"className\"in this){if(b===a)return X(this,\"\");d=X(this),V(this,b,c,d).split(/\\s+/g).forEach(function(a){d=d.replace(P(a),\" \")}),X(this,d.trim())}})},toggleClass:function(b,d){return b?this.each(function(e){var f=c(this),g=V(this,b,e,X(this));g.split(/\\s+/g).forEach(function(b){(d===a?!f.hasClass(b):d)?f.addClass(b):f.removeClass(b)})}):this},scrollTop:function(b){if(this.length){var c=\"scrollTop\"in this[0];return b===a?c?this[0].scrollTop:this[0].pageYOffset:this.each(c?function(){this.scrollTop=b}:function(){this.scrollTo(this.scrollX,b)})}},scrollLeft:function(b){if(this.length){var c=\"scrollLeft\"in this[0];return b===a?c?this[0].scrollLeft:this[0].pageXOffset:this.each(c?function(){this.scrollLeft=b}:function(){this.scrollTo(b,this.scrollY)})}},position:function(){if(this.length){var a=this[0],b=this.offsetParent(),d=this.offset(),e=o.test(b[0].nodeName)?{top:0,left:0}:b.offset();return d.top-=parseFloat(c(a).css(\"margin-top\"))||0,d.left-=parseFloat(c(a).css(\"margin-left\"))||0,e.top+=parseFloat(c(b[0]).css(\"border-top-width\"))||0,e.left+=parseFloat(c(b[0]).css(\"border-left-width\"))||0,{top:d.top-e.top,left:d.left-e.left}}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||h.body;a&&!o.test(a.nodeName)&&\"static\"==c(a).css(\"position\");)a=a.offsetParent;return a})}},c.fn.detach=c.fn.remove,[\"width\",\"height\"].forEach(function(b){var d=b.replace(/./,function(a){return a[0].toUpperCase()});c.fn[b]=function(e){var f,g=this[0];return e===a?H(g)?g[\"inner\"+d]:I(g)?g.documentElement[\"scroll\"+d]:(f=this.offset())&&f[b]:this.each(function(a){g=c(this),g.css(b,V(this,e,a,g[b]()))})}}),r.forEach(function(a,b){var d=b%2;c.fn[a]=function(){var a,f,e=c.map(arguments,function(b){return a=F(b),\"object\"==a||\"array\"==a||null==b?b:z.fragment(b)}),g=this.length>1;return e.length<1?this:this.each(function(a,i){f=d?i:i.parentNode,i=0==b?i.nextSibling:1==b?i.firstChild:2==b?i:null;var j=c.contains(h.documentElement,f);e.forEach(function(a){if(g)a=a.cloneNode(!0);else if(!f)return c(a).remove();f.insertBefore(a,i),j&&Z(a,function(a){null==a.nodeName||\"SCRIPT\"!==a.nodeName.toUpperCase()||a.type&&\"text/javascript\"!==a.type||a.src||window.eval.call(window,a.innerHTML)})})})},c.fn[d?a+\"To\":\"insert\"+(b?\"Before\":\"After\")]=function(b){return c(b)[a](this),this}}),z.Z.prototype=c.fn,z.uniq=B,z.deserializeValue=Y,c.zepto=z,c}();window.Zepto=Zepto,void 0===window.$&&(window.$=Zepto),function(a){function l(a){return a._zid||(a._zid=b++)}function m(a,b,c,d){if(b=n(b),b.ns)var e=o(b.ns);return(g[l(a)]||[]).filter(function(a){return!(!a||b.e&&a.e!=b.e||b.ns&&!e.test(a.ns)||c&&l(a.fn)!==l(c)||d&&a.sel!=d)})}function n(a){var b=(\"\"+a).split(\".\");return{e:b[0],ns:b.slice(1).sort().join(\" \")}}function o(a){return new RegExp(\"(?:^| )\"+a.replace(\" \",\" .* ?\")+\"(?: |$)\")}function p(a,b){return a.del&&!i&&a.e in j||!!b}function q(a){return k[a]||i&&j[a]||a}function r(b,d,e,f,h,i,j){var m=l(b),o=g[m]||(g[m]=[]);d.split(/\\s/).forEach(function(d){if(\"ready\"==d)return a(document).ready(e);var g=n(d);g.fn=e,g.sel=h,g.e in k&&(e=function(b){var c=b.relatedTarget;return!c||c!==this&&!a.contains(this,c)?g.fn.apply(this,arguments):void 0}),g.del=i;var l=i||e;g.proxy=function(a){if(a=x(a),!a.isImmediatePropagationStopped()){a.data=f;var d=l.apply(b,a._args==c?[a]:[a].concat(a._args));return d===!1&&(a.preventDefault(),a.stopPropagation()),d}},g.i=o.length,o.push(g),\"addEventListener\"in b&&b.addEventListener(q(g.e),g.proxy,p(g,j))})}function s(a,b,c,d,e){var f=l(a);(b||\"\").split(/\\s/).forEach(function(b){m(a,b,c,d).forEach(function(b){delete g[f][b.i],\"removeEventListener\"in a&&a.removeEventListener(q(b.e),b.proxy,p(b,e))})})}function x(b,d){return(d||!b.isDefaultPrevented)&&(d||(d=b),a.each(w,function(a,c){var e=d[a];b[a]=function(){return this[c]=t,e&&e.apply(d,arguments)},b[c]=u}),(d.defaultPrevented!==c?d.defaultPrevented:\"returnValue\"in d?d.returnValue===!1:d.getPreventDefault&&d.getPreventDefault())&&(b.isDefaultPrevented=t)),b}function y(a){var b,d={originalEvent:a};for(b in a)v.test(b)||a[b]===c||(d[b]=a[b]);return x(d,a)}var c,b=1,d=Array.prototype.slice,e=a.isFunction,f=function(a){return\"string\"==typeof a},g={},h={},i=\"onfocusin\"in window,j={focus:\"focusin\",blur:\"focusout\"},k={mouseenter:\"mouseover\",mouseleave:\"mouseout\"};h.click=h.mousedown=h.mouseup=h.mousemove=\"MouseEvents\",a.event={add:r,remove:s},a.proxy=function(b,c){var g=2 in arguments&&d.call(arguments,2);if(e(b)){var h=function(){return b.apply(c,g?g.concat(d.call(arguments)):arguments)};return h._zid=l(b),h}if(f(c))return g?(g.unshift(b[c],b),a.proxy.apply(null,g)):a.proxy(b[c],b);throw new TypeError(\"expected function\")},a.fn.bind=function(a,b,c){return this.on(a,b,c)},a.fn.unbind=function(a,b){return this.off(a,b)},a.fn.one=function(a,b,c,d){return this.on(a,b,c,d,1)};var t=function(){return!0},u=function(){return!1},v=/^([A-Z]|returnValue$|layer[XY]$)/,w={preventDefault:\"isDefaultPrevented\",stopImmediatePropagation:\"isImmediatePropagationStopped\",stopPropagation:\"isPropagationStopped\"};a.fn.delegate=function(a,b,c){return this.on(b,a,c)},a.fn.undelegate=function(a,b,c){return this.off(b,a,c)},a.fn.live=function(b,c){return a(document.body).delegate(this.selector,b,c),this},a.fn.die=function(b,c){return a(document.body).undelegate(this.selector,b,c),this},a.fn.on=function(b,g,h,i,j){var k,l,m=this;return b&&!f(b)?(a.each(b,function(a,b){m.on(a,g,h,b,j)}),m):(f(g)||e(i)||i===!1||(i=h,h=g,g=c),(e(h)||h===!1)&&(i=h,h=c),i===!1&&(i=u),m.each(function(c,e){j&&(k=function(a){return s(e,a.type,i),i.apply(this,arguments)}),g&&(l=function(b){var c,f=a(b.target).closest(g,e).get(0);return f&&f!==e?(c=a.extend(y(b),{currentTarget:f,liveFired:e}),(k||i).apply(f,[c].concat(d.call(arguments,1)))):void 0}),r(e,b,i,h,g,l||k)}))},a.fn.off=function(b,d,g){var h=this;return b&&!f(b)?(a.each(b,function(a,b){h.off(a,d,b)}),h):(f(d)||e(g)||g===!1||(g=d,d=c),g===!1&&(g=u),h.each(function(){s(this,b,g,d)}))},a.fn.trigger=function(b,c){return b=f(b)||a.isPlainObject(b)?a.Event(b):x(b),b._args=c,this.each(function(){b.type in j&&\"function\"==typeof this[b.type]?this[b.type]():\"dispatchEvent\"in this?this.dispatchEvent(b):a(this).triggerHandler(b,c)})},a.fn.triggerHandler=function(b,c){var d,e;return this.each(function(g,h){d=y(f(b)?a.Event(b):b),d._args=c,d.target=h,a.each(m(h,b.type||b),function(a,b){return e=b.proxy(d),d.isImmediatePropagationStopped()?!1:void 0})}),e},\"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error\".split(\" \").forEach(function(b){a.fn[b]=function(a){return 0 in arguments?this.bind(b,a):this.trigger(b)}}),a.Event=function(a,b){f(a)||(b=a,a=b.type);var c=document.createEvent(h[a]||\"Events\"),d=!0;if(b)for(var e in b)\"bubbles\"==e?d=!!b[e]:c[e]=b[e];return c.initEvent(a,d,!0),x(c)}}(Zepto),function(a){function m(b,c,d){var e=a.Event(c);return a(b).trigger(e,d),!e.isDefaultPrevented()}function n(a,b,d,e){return a.global?m(b||c,d,e):void 0}function o(b){b.global&&0===a.active++&&n(b,null,\"ajaxStart\")}function p(b){b.global&&!--a.active&&n(b,null,\"ajaxStop\")}function q(a,b){var c=b.context;return b.beforeSend.call(c,a,b)===!1||n(b,c,\"ajaxBeforeSend\",[a,b])===!1?!1:(n(b,c,\"ajaxSend\",[a,b]),void 0)}function r(a,b,c,d){var e=c.context,f=\"success\";c.success.call(e,a,f,b),d&&d.resolveWith(e,[a,f,b]),n(c,e,\"ajaxSuccess\",[b,c,a]),t(f,b,c)}function s(a,b,c,d,e){var f=d.context;d.error.call(f,c,b,a),e&&e.rejectWith(f,[c,b,a]),n(d,f,\"ajaxError\",[c,d,a||b]),t(b,c,d)}function t(a,b,c){var d=c.context;c.complete.call(d,b,a),n(c,d,\"ajaxComplete\",[b,c]),p(c)}function u(){}function v(a){return a&&(a=a.split(\";\",2)[0]),a&&(a==j?\"html\":a==i?\"json\":g.test(a)?\"script\":h.test(a)&&\"xml\")||\"text\"}function w(a,b){return\"\"==b?a:(a+\"&\"+b).replace(/[&?]{1,2}/,\"?\")}function x(b){b.processData&&b.data&&\"string\"!=a.type(b.data)&&(b.data=a.param(b.data,b.traditional)),!b.data||b.type&&\"GET\"!=b.type.toUpperCase()||(b.url=w(b.url,b.data),b.data=void 0)}function y(b,c,d,e){return a.isFunction(c)&&(e=d,d=c,c=void 0),a.isFunction(d)||(e=d,d=void 0),{url:b,data:c,success:d,dataType:e}}function A(b,c,d,e){var f,g=a.isArray(c),h=a.isPlainObject(c);a.each(c,function(c,i){f=a.type(i),e&&(c=d?e:e+\"[\"+(h||\"object\"==f||\"array\"==f?c:\"\")+\"]\"),!e&&g?b.add(i.name,i.value):\"array\"==f||!d&&\"object\"==f?A(b,i,d,c):b.add(c,i)})}var d,e,b=0,c=window.document,f=/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,g=/^(?:text|application)\\/javascript/i,h=/^(?:text|application)\\/xml/i,i=\"application/json\",j=\"text/html\",k=/^\\s*$/,l=c.createElement(\"a\");l.href=window.location.href,a.active=0,a.ajaxJSONP=function(d,e){if(!(\"type\"in d))return a.ajax(d);var j,m,f=d.jsonpCallback,g=(a.isFunction(f)?f():f)||\"jsonp\"+ ++b,h=c.createElement(\"script\"),i=window[g],k=function(b){a(h).triggerHandler(\"error\",b||\"abort\")},l={abort:k};return e&&e.promise(l),a(h).on(\"load error\",function(b,c){clearTimeout(m),a(h).off().remove(),\"error\"!=b.type&&j?r(j[0],l,d,e):s(null,c||\"error\",l,d,e),window[g]=i,j&&a.isFunction(i)&&i(j[0]),i=j=void 0}),q(l,d)===!1?(k(\"abort\"),l):(window[g]=function(){j=arguments},h.src=d.url.replace(/\\?(.+)=\\?/,\"?$1=\"+g),c.head.appendChild(h),d.timeout>0&&(m=setTimeout(function(){k(\"timeout\")},d.timeout)),l)},a.ajaxSettings={type:\"GET\",beforeSend:u,success:u,error:u,complete:u,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:\"text/javascript, application/javascript, application/x-javascript\",json:i,xml:\"application/xml, text/xml\",html:j,text:\"text/plain\"},crossDomain:!1,timeout:0,processData:!0,cache:!0},a.ajax=function(b){var h,f=a.extend({},b||{}),g=a.Deferred&&a.Deferred();for(d in a.ajaxSettings)void 0===f[d]&&(f[d]=a.ajaxSettings[d]);o(f),f.crossDomain||(h=c.createElement(\"a\"),h.href=f.url,h.href=h.href,f.crossDomain=l.protocol+\"//\"+l.host!=h.protocol+\"//\"+h.host),f.url||(f.url=window.location.toString()),x(f);var i=f.dataType,j=/\\?.+=\\?/.test(f.url);if(j&&(i=\"jsonp\"),f.cache!==!1&&(b&&b.cache===!0||\"script\"!=i&&\"jsonp\"!=i)||(f.url=w(f.url,\"_=\"+Date.now())),\"jsonp\"==i)return j||(f.url=w(f.url,f.jsonp?f.jsonp+\"=?\":f.jsonp===!1?\"\":\"callback=?\")),a.ajaxJSONP(f,g);var A,m=f.accepts[i],n={},p=function(a,b){n[a.toLowerCase()]=[a,b]},t=/^([\\w-]+:)\\/\\//.test(f.url)?RegExp.$1:window.location.protocol,y=f.xhr(),z=y.setRequestHeader;if(g&&g.promise(y),f.crossDomain||p(\"X-Requested-With\",\"XMLHttpRequest\"),p(\"Accept\",m||\"*/*\"),(m=f.mimeType||m)&&(m.indexOf(\",\")>-1&&(m=m.split(\",\",2)[0]),y.overrideMimeType&&y.overrideMimeType(m)),(f.contentType||f.contentType!==!1&&f.data&&\"GET\"!=f.type.toUpperCase())&&p(\"Content-Type\",f.contentType||\"application/x-www-form-urlencoded\"),f.headers)for(e in f.headers)p(e,f.headers[e]);if(y.setRequestHeader=p,y.onreadystatechange=function(){if(4==y.readyState){y.onreadystatechange=u,clearTimeout(A);var b,c=!1;if(y.status>=200&&y.status<300||304==y.status||0==y.status&&\"file:\"==t){i=i||v(f.mimeType||y.getResponseHeader(\"content-type\")),b=y.responseText;try{\"script\"==i?(1,eval)(b):\"xml\"==i?b=y.responseXML:\"json\"==i&&(b=k.test(b)?null:a.parseJSON(b))}catch(d){c=d}c?s(c,\"parsererror\",y,f,g):r(b,y,f,g)}else s(y.statusText||null,y.status?\"error\":\"abort\",y,f,g)}},q(y,f)===!1)return y.abort(),s(null,\"abort\",y,f,g),y;if(f.xhrFields)for(e in f.xhrFields)y[e]=f.xhrFields[e];var B=\"async\"in f?f.async:!0;y.open(f.type,f.url,B,f.username,f.password);for(e in n)z.apply(y,n[e]);return f.timeout>0&&(A=setTimeout(function(){y.onreadystatechange=u,y.abort(),s(null,\"timeout\",y,f,g)},f.timeout)),y.send(f.data?f.data:null),y},a.get=function(){return a.ajax(y.apply(null,arguments))},a.post=function(){var b=y.apply(null,arguments);return b.type=\"POST\",a.ajax(b)},a.getJSON=function(){var b=y.apply(null,arguments);return b.dataType=\"json\",a.ajax(b)},a.fn.load=function(b,c,d){if(!this.length)return this;var h,e=this,g=b.split(/\\s/),i=y(b,c,d),j=i.success;return g.length>1&&(i.url=g[0],h=g[1]),i.success=function(b){e.html(h?a(\"<div>\").html(b.replace(f,\"\")).find(h):b),j&&j.apply(e,arguments)},a.ajax(i),this};var z=encodeURIComponent;a.param=function(b,c){var d=[];return d.add=function(b,c){a.isFunction(c)&&(c=c()),null==c&&(c=\"\"),this.push(z(b)+\"=\"+z(c))},A(d,b,c),d.join(\"&\").replace(/%20/g,\"+\")}}(Zepto),function(a){a.fn.serializeArray=function(){var b,c,d=[],e=function(a){return a.forEach?a.forEach(e):(d.push({name:b,value:a}),void 0)};return this[0]&&a.each(this[0].elements,function(d,f){c=f.type,b=f.name,b&&\"fieldset\"!=f.nodeName.toLowerCase()&&!f.disabled&&\"submit\"!=c&&\"reset\"!=c&&\"button\"!=c&&\"file\"!=c&&(\"radio\"!=c&&\"checkbox\"!=c||f.checked)&&e(a(f).val())}),d},a.fn.serialize=function(){var a=[];return this.serializeArray().forEach(function(b){a.push(encodeURIComponent(b.name)+\"=\"+encodeURIComponent(b.value))}),a.join(\"&\")},a.fn.submit=function(b){if(0 in arguments)this.bind(\"submit\",b);else if(this.length){var c=a.Event(\"submit\");this.eq(0).trigger(c),c.isDefaultPrevented()||this.get(0).submit()}return this}}(Zepto),function(a){\"__proto__\"in{}||a.extend(a.zepto,{Z:function(b,c){return b=b||[],a.extend(b,a.fn),b.selector=c||\"\",b.__Z=!0,b},isZ:function(b){return\"array\"===a.type(b)&&\"__Z\"in b}});try{getComputedStyle(void 0)}catch(b){var c=getComputedStyle;window.getComputedStyle=function(a){try{return c(a)}catch(b){return null}}}}(Zepto),function(a){function g(f,g){var i=f[e],j=i&&b[i];if(void 0===g)return j||h(f);if(j){if(g in j)return j[g];var k=d(g);if(k in j)return j[k]}return c.call(a(f),g)}function h(c,f,g){var h=c[e]||(c[e]=++a.uuid),j=b[h]||(b[h]=i(c));return void 0!==f&&(j[d(f)]=g),j}function i(b){var c={};return a.each(b.attributes||f,function(b,e){0==e.name.indexOf(\"data-\")&&(c[d(e.name.replace(\"data-\",\"\"))]=a.zepto.deserializeValue(e.value))}),c}var b={},c=a.fn.data,d=a.camelCase,e=a.expando=\"Zepto\"+ +new Date,f=[];a.fn.data=function(b,c){return void 0===c?a.isPlainObject(b)?this.each(function(c,d){a.each(b,function(a,b){h(d,a,b)})}):0 in this?g(this[0],b):void 0:this.each(function(){h(this,b,c)})},a.fn.removeData=function(c){return\"string\"==typeof c&&(c=c.split(/\\s+/)),this.each(function(){var f=this[e],g=f&&b[f];g&&a.each(c||g,function(a){delete g[c?d(this):a]})})},[\"remove\",\"empty\"].forEach(function(b){var c=a.fn[b];a.fn[b]=function(){var a=this.find(\"*\");return\"remove\"===b&&(a=a.add(this)),a.removeData(),c.call(this)}})}(Zepto);\n//ChartJS\n(function(){\"use strict\";var t=this,i=t.Chart,e=function(t){this.canvas=t.canvas,this.ctx=t;var i=function(t,i){return t[\"offset\"+i]?t[\"offset\"+i]:document.defaultView.getComputedStyle(t).getPropertyValue(i)},e=this.width=i(t.canvas,\"Width\"),n=this.height=i(t.canvas,\"Height\");t.canvas.width=e,t.canvas.height=n;var e=this.width=t.canvas.width,n=this.height=t.canvas.height;return this.aspectRatio=this.width/this.height,s.retinaScale(this),this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:\"easeOutQuart\",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:\"rgba(0,0,0,.1)\",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:\"<%=value%>\",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:\"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif\",scaleFontSize:12,scaleFontStyle:\"normal\",scaleFontColor:\"#666\",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:[\"mousemove\",\"touchstart\",\"touchmove\",\"mouseout\"],tooltipFillColor:\"rgba(0,0,0,0.8)\",tooltipFontFamily:\"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif\",tooltipFontSize:14,tooltipFontStyle:\"normal\",tooltipFontColor:\"#fff\",tooltipTitleFontFamily:\"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif\",tooltipTitleFontSize:14,tooltipTitleFontStyle:\"bold\",tooltipTitleFontColor:\"#fff\",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:\"<%if (label){%><%=label%>: <%}%><%= value %>\",multiTooltipTemplate:\"<%= value %>\",multiTooltipKeyBackground:\"#fff\",onAnimationProgress:function(){},onAnimationComplete:function(){}}},e.types={};var s=e.helpers={},n=s.each=function(t,i,e){var s=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var n;for(n=0;n<t.length;n++)i.apply(e,[t[n],n].concat(s))}else for(var o in t)i.apply(e,[t[o],o].concat(s))},o=s.clone=function(t){var i={};return n(t,function(e,s){t.hasOwnProperty(s)&&(i[s]=e)}),i},a=s.extend=function(t){return n(Array.prototype.slice.call(arguments,1),function(i){n(i,function(e,s){i.hasOwnProperty(s)&&(t[s]=e)})}),t},h=s.merge=function(){var t=Array.prototype.slice.call(arguments,0);return t.unshift({}),a.apply(null,t)},l=s.indexOf=function(t,i){if(Array.prototype.indexOf)return t.indexOf(i);for(var e=0;e<t.length;e++)if(t[e]===i)return e;return-1},r=(s.where=function(t,i){var e=[];return s.each(t,function(t){i(t)&&e.push(t)}),e},s.findNextWhere=function(t,i,e){e||(e=-1);for(var s=e+1;s<t.length;s++){var n=t[s];if(i(n))return n}},s.findPreviousWhere=function(t,i,e){e||(e=t.length);for(var s=e-1;s>=0;s--){var n=t[s];if(i(n))return n}},s.inherits=function(t){var i=this,e=t&&t.hasOwnProperty(\"constructor\")?t.constructor:function(){return i.apply(this,arguments)},s=function(){this.constructor=e};return s.prototype=i.prototype,e.prototype=new s,e.extend=r,t&&a(e.prototype,t),e.__super__=i.prototype,e}),c=s.noop=function(){},u=s.uid=function(){var t=0;return function(){return\"chart-\"+t++}}(),d=s.warn=function(t){window.console&&\"function\"==typeof window.console.warn&&console.warn(t)},p=s.amd=\"function\"==typeof define&&define.amd,f=s.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},g=s.max=function(t){return Math.max.apply(Math,t)},m=s.min=function(t){return Math.min.apply(Math,t)},v=(s.cap=function(t,i,e){if(f(i)){if(t>i)return i}else if(f(e)&&e>t)return e;return t},s.getDecimalPlaces=function(t){return t%1!==0&&f(t)?t.toString().split(\".\")[1].length:0}),S=s.radians=function(t){return t*(Math.PI/180)},x=(s.getAngleFromPoint=function(t,i){var e=i.x-t.x,s=i.y-t.y,n=Math.sqrt(e*e+s*s),o=2*Math.PI+Math.atan2(s,e);return 0>e&&0>s&&(o+=2*Math.PI),{angle:o,distance:n}},s.aliasPixel=function(t){return t%2===0?0:.5}),y=(s.splineCurve=function(t,i,e,s){var n=Math.sqrt(Math.pow(i.x-t.x,2)+Math.pow(i.y-t.y,2)),o=Math.sqrt(Math.pow(e.x-i.x,2)+Math.pow(e.y-i.y,2)),a=s*n/(n+o),h=s*o/(n+o);return{inner:{x:i.x-a*(e.x-t.x),y:i.y-a*(e.y-t.y)},outer:{x:i.x+h*(e.x-t.x),y:i.y+h*(e.y-t.y)}}},s.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),C=(s.calculateScaleRange=function(t,i,e,s,n){var o=2,a=Math.floor(i/(1.5*e)),h=o>=a,l=g(t),r=m(t);l===r&&(l+=.5,r>=.5&&!s?r-=.5:l+=.5);for(var c=Math.abs(l-r),u=y(c),d=Math.ceil(l/(1*Math.pow(10,u)))*Math.pow(10,u),p=s?0:Math.floor(r/(1*Math.pow(10,u)))*Math.pow(10,u),f=d-p,v=Math.pow(10,u),S=Math.round(f/v);(S>a||a>2*S)&&!h;)if(S>a)v*=2,S=Math.round(f/v),S%1!==0&&(h=!0);else if(n&&u>=0){if(v/2%1!==0)break;v/=2,S=Math.round(f/v)}else v/=2,S=Math.round(f/v);return h&&(S=o,v=f/S),{steps:S,stepValue:v,min:p,max:p+S*v}},s.template=function(t,i){function e(t,i){var e=/\\W/.test(t)?new Function(\"obj\",\"var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('\"+t.replace(/[\\r\\t\\n]/g,\" \").split(\"<%\").join(\"\t\").replace(/((^|%>)[^\\t]*)'/g,\"$1\\r\").replace(/\\t=(.*?)%>/g,\"',$1,'\").split(\"\t\").join(\"');\").split(\"%>\").join(\"p.push('\").split(\"\\r\").join(\"\\\\'\")+\"');}return p.join('');\"):s[t]=s[t];return i?e(i):e}if(t instanceof Function)return t(i);var s={};return e(t,i)}),w=(s.generateLabels=function(t,i,e,s){var o=new Array(i);return labelTemplateString&&n(o,function(i,n){o[n]=C(t,{value:e+s*(n+1)})}),o},s.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),-(s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)))},easeOutElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),s*Math.pow(2,-10*t)*Math.sin(2*(1*t-i)*Math.PI/e)+1)},easeInOutElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:2==(t/=.5)?1:(e||(e=.3*1.5),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),1>t?-.5*s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e):s*Math.pow(2,-10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)*.5+1)},easeInBack:function(t){var i=1.70158;return 1*(t/=1)*t*((i+1)*t-i)},easeOutBack:function(t){var i=1.70158;return 1*((t=t/1-1)*t*((i+1)*t+i)+1)},easeInOutBack:function(t){var i=1.70158;return(t/=.5)<1?.5*t*t*(((i*=1.525)+1)*t-i):.5*((t-=2)*t*(((i*=1.525)+1)*t+i)+2)},easeInBounce:function(t){return 1-w.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?7.5625*t*t:2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*w.easeInBounce(2*t):.5*w.easeOutBounce(2*t-1)+.5}}),b=s.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),P=s.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),L=(s.animationLoop=function(t,i,e,s,n,o){var a=0,h=w[e]||w.linear,l=function(){a++;var e=a/i,r=h(e);t.call(o,r,e,a),s.call(o,r,e),i>a?o.animationFrame=b(l):n.apply(o)};b(l)},s.getRelativePosition=function(t){var i,e,s=t.originalEvent||t,n=t.currentTarget||t.srcElement,o=n.getBoundingClientRect();return s.touches?(i=s.touches[0].clientX-o.left,e=s.touches[0].clientY-o.top):(i=s.clientX-o.left,e=s.clientY-o.top),{x:i,y:e}},s.addEvent=function(t,i,e){t.addEventListener?t.addEventListener(i,e):t.attachEvent?t.attachEvent(\"on\"+i,e):t[\"on\"+i]=e}),k=s.removeEvent=function(t,i,e){t.removeEventListener?t.removeEventListener(i,e,!1):t.detachEvent?t.detachEvent(\"on\"+i,e):t[\"on\"+i]=c},F=(s.bindEvents=function(t,i,e){t.events||(t.events={}),n(i,function(i){t.events[i]=function(){e.apply(t,arguments)},L(t.chart.canvas,i,t.events[i])})},s.unbindEvents=function(t,i){n(i,function(i,e){k(t.chart.canvas,e,i)})}),R=s.getMaximumWidth=function(t){var i=t.parentNode;return i.clientWidth},T=s.getMaximumHeight=function(t){var i=t.parentNode;return i.clientHeight},A=(s.getMaximumSize=s.getMaximumWidth,s.retinaScale=function(t){var i=t.ctx,e=t.canvas.width,s=t.canvas.height;window.devicePixelRatio&&(i.canvas.style.width=e+\"px\",i.canvas.style.height=s+\"px\",i.canvas.height=s*window.devicePixelRatio,i.canvas.width=e*window.devicePixelRatio,i.scale(window.devicePixelRatio,window.devicePixelRatio))}),M=s.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},W=s.fontString=function(t,i,e){return i+\" \"+t+\"px \"+e},z=s.longestText=function(t,i,e){t.font=i;var s=0;return n(e,function(i){var e=t.measureText(i).width;s=e>s?e:s}),s},B=s.drawRoundedRectangle=function(t,i,e,s,n,o){t.beginPath(),t.moveTo(i+o,e),t.lineTo(i+s-o,e),t.quadraticCurveTo(i+s,e,i+s,e+o),t.lineTo(i+s,e+n-o),t.quadraticCurveTo(i+s,e+n,i+s-o,e+n),t.lineTo(i+o,e+n),t.quadraticCurveTo(i,e+n,i,e+n-o),t.lineTo(i,e+o),t.quadraticCurveTo(i,e,i+o,e),t.closePath()};e.instances={},e.Type=function(t,i,s){this.options=i,this.chart=s,this.id=u(),e.instances[this.id]=this,i.responsive&&this.resize(),this.initialize.call(this,t)},a(e.Type.prototype,{initialize:function(){return this},clear:function(){return M(this.chart),this},stop:function(){return P(this.animationFrame),this},resize:function(t){this.stop();var i=this.chart.canvas,e=R(this.chart.canvas),s=this.options.maintainAspectRatio?e/this.chart.aspectRatio:T(this.chart.canvas);return i.width=this.chart.width=e,i.height=this.chart.height=s,A(this.chart),\"function\"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){return t&&this.reflow(),this.options.animation&&!t?s.animationLoop(this.draw,this.options.animationSteps,this.options.animationEasing,this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this.draw(),this.options.onAnimationComplete.call(this)),this},generateLegend:function(){return C(this.options.legendTemplate,this)},destroy:function(){this.clear(),F(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty(\"width\"),t.style.removeProperty(\"height\")):(t.style.removeAttribute(\"width\"),t.style.removeAttribute(\"height\")),delete e.instances[this.id]},showTooltip:function(t,i){\"undefined\"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var i=!1;return t.length!==this.activeElements.length?i=!0:(n(t,function(t,e){t!==this.activeElements[e]&&(i=!0)},this),i)}.call(this,t);if(o||i){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,h,r=this.datasets.length-1;r>=0&&(a=this.datasets[r].points||this.datasets[r].bars||this.datasets[r].segments,h=l(a,t[0]),-1===h);r--);var c=[],u=[],d=function(){var t,i,e,n,o,a=[],l=[],r=[];return s.each(this.datasets,function(i){t=i.points||i.bars||i.segments,t[h]&&t[h].hasValue()&&a.push(t[h])}),s.each(a,function(t){l.push(t.x),r.push(t.y),c.push(s.template(this.options.multiTooltipTemplate,t)),u.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),o=m(r),e=g(r),n=m(l),i=g(l),{x:n>this.chart.width/2?n:i,y:(o+e)/2}}.call(this,h);new e.MultiTooltip({x:d.x,y:d.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:u,legendColorBackground:this.options.multiTooltipKeyBackground,title:t[0].label,chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else n(t,function(t){var i=t.tooltipPosition();new e.Tooltip({x:Math.round(i.x),y:Math.round(i.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:C(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),e.Type.extend=function(t){var i=this,s=function(){return i.apply(this,arguments)};if(s.prototype=o(i.prototype),a(s.prototype,t),s.extend=e.Type.extend,t.name||i.prototype.name){var n=t.name||i.prototype.name,l=e.defaults[i.prototype.name]?o(e.defaults[i.prototype.name]):{};e.defaults[n]=a(l,t.defaults),e.types[n]=s,e.prototype[n]=function(t,i){var o=h(e.defaults.global,e.defaults[n],i||{});return new s(t,o,this)}}else d(\"Name not provided for this chart, so it hasn't been registered\");return i},e.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(e.Element.prototype,{initialize:function(){},restore:function(t){return t?n(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return n(t,function(t,i){this._saved[i]=this[i],this[i]=t},this),this},transition:function(t,i){return n(t,function(t,e){this[e]=(t-this._saved[e])*i+this._saved[e]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return f(this.value)}}),e.Element.extend=r,e.Point=e.Element.extend({display:!0,inRange:function(t,i){var e=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(i-this.y,2)<Math.pow(e,2)},draw:function(){if(this.display){var t=this.ctx;t.beginPath(),t.arc(this.x,this.y,this.radius,0,2*Math.PI),t.closePath(),t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.fillStyle=this.fillColor,t.fill(),t.stroke()}}}),e.Arc=e.Element.extend({inRange:function(t,i){var e=s.getAngleFromPoint(this,{x:t,y:i}),n=e.angle>=this.startAngle&&e.angle<=this.endAngle,o=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return n&&o},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,i=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*i,y:this.y+Math.sin(t)*i}},draw:function(t){var i=this.ctx;i.beginPath(),i.arc(this.x,this.y,this.outerRadius,this.startAngle,this.endAngle),i.arc(this.x,this.y,this.innerRadius,this.endAngle,this.startAngle,!0),i.closePath(),i.strokeStyle=this.strokeColor,i.lineWidth=this.strokeWidth,i.fillStyle=this.fillColor,i.fill(),i.lineJoin=\"bevel\",this.showStroke&&i.stroke()}}),e.Rectangle=e.Element.extend({draw:function(){var t=this.ctx,i=this.width/2,e=this.x-i,s=this.x+i,n=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(e+=o,s-=o,n+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(e,this.base),t.lineTo(e,n),t.lineTo(s,n),t.lineTo(s,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,i){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&i>=this.y&&i<=this.base}}),e.Tooltip=e.Element.extend({draw:function(){var t=this.chart.ctx;t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign=\"center\",this.yAlign=\"above\";var i=this.caretPadding=2,e=t.measureText(this.text).width+2*this.xPadding,s=this.fontSize+2*this.yPadding,n=s+this.caretHeight+i;this.x+e/2>this.chart.width?this.xAlign=\"left\":this.x-e/2<0&&(this.xAlign=\"right\"),this.y-n<0&&(this.yAlign=\"below\");var o=this.x-e/2,a=this.y-n;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case\"above\":t.beginPath(),t.moveTo(this.x,this.y-i),t.lineTo(this.x+this.caretHeight,this.y-(i+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(i+this.caretHeight)),t.closePath(),t.fill();break;case\"below\":a=this.y+i+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+i),t.lineTo(this.x+this.caretHeight,this.y+i+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+i+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case\"left\":o=this.x-e+(this.cornerRadius+this.caretHeight);break;case\"right\":o=this.x-(this.cornerRadius+this.caretHeight)}B(t,o,a,e,s,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign=\"center\",t.textBaseline=\"middle\",t.fillText(this.text,o+e/2,a+s/2)}}}),e.MultiTooltip=e.Element.extend({initialize:function(){this.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=W(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+1.5*this.titleFontSize,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,i=z(this.ctx,this.font,this.labels)+this.fontSize+3,e=g([i,t]);this.width=e+2*this.xPadding;var s=this.height/2;this.y-s<0?this.y=s:this.y+s>this.chart.height&&(this.y=this.chart.height-s),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var i=this.y-this.height/2+this.yPadding,e=t-1;return 0===t?i+this.titleFontSize/2:i+(1.5*this.fontSize*e+this.fontSize/2)+1.5*this.titleFontSize},draw:function(){if(this.custom)this.custom(this);else{B(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign=\"left\",t.textBaseline=\"middle\",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,s.each(this.labels,function(i,e){t.fillStyle=this.textColor,t.fillText(i,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(e+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[e].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?z(this.ctx,this.font,this.yLabels):0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,i=this.endPoint-this.startPoint;for(this.calculateYRange(i),this.buildYLabels(),this.calculateXLabelRotation();i>this.endPoint-this.startPoint;)i=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(i),this.buildYLabels(),t<this.yLabelWidth&&this.calculateXLabelRotation()},calculateXLabelRotation:function(){this.ctx.font=this.font;var t,i,e=this.ctx.measureText(this.xLabels[0]).width,s=this.ctx.measureText(this.xLabels[this.xLabels.length-1]).width;if(this.xScalePaddingRight=s/2+3,this.xScalePaddingLeft=e/2>this.yLabelWidth+10?e/2:this.yLabelWidth+10,this.xLabelRotation=0,this.display){var n,o=z(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)n=Math.cos(S(this.xLabelRotation)),t=n*e,i=n*s,t+this.fontSize/2>this.yLabelWidth+8&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=n*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(S(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var i=this.drawingArea()/(this.min-this.max);return this.endPoint-i*(t-this.min)},calculateX:function(t){var i=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),e=i/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),s=e*t+this.xScalePaddingLeft;return this.offsetGridLines&&(s+=e/2),Math.round(s)},update:function(t){s.extend(this,t),this.fit()},draw:function(){var t=this.ctx,i=(this.endPoint-this.startPoint)/this.steps,e=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,n(this.yLabels,function(n,o){var a=this.endPoint-i*o,h=Math.round(a),l=this.showHorizontalLines;t.textAlign=\"right\",t.textBaseline=\"middle\",this.showLabels&&t.fillText(n,e-10,a),0!==o||l||(l=!0),l&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),h+=s.aliasPixel(t.lineWidth),l&&(t.moveTo(e,h),t.lineTo(this.width,h),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(e-5,h),t.lineTo(e,h),t.stroke(),t.closePath()},this),n(this.xLabels,function(i,e){var s=this.calculateX(e)+x(this.lineWidth),n=this.calculateX(e-(this.offsetGridLines?.5:0))+x(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==e||a||(a=!0),a&&t.beginPath(),e>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(n,this.endPoint),t.lineTo(n,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(n,this.endPoint),t.lineTo(n,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(s,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*S(this.xLabelRotation)),t.font=this.font,t.textAlign=o?\"right\":\"center\",t.textBaseline=o?\"middle\":\"top\",t.fillText(i,0,0),t.restore()},this))}}),e.RadialScale=e.Element.extend({initialize:function(){this.size=m([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var i=this.drawingArea/(this.max-this.min);return(t-this.min)*i},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,i,e,s,n,o,a,h,l,r,c,u,d=m([this.height/2-this.pointLabelFontSize-5,this.width/2]),p=this.width,g=0;for(this.ctx.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),i=0;i<this.valuesCount;i++)t=this.getPointPosition(i,d),e=this.ctx.measureText(C(this.templateString,{value:this.labels[i]})).width+5,0===i||i===this.valuesCount/2?(s=e/2,t.x+s>p&&(p=t.x+s,n=i),t.x-s<g&&(g=t.x-s,a=i)):i<this.valuesCount/2?t.x+e>p&&(p=t.x+e,n=i):i>this.valuesCount/2&&t.x-e<g&&(g=t.x-e,a=i);l=g,r=Math.ceil(p-this.width),o=this.getIndexAngle(n),h=this.getIndexAngle(a),c=r/Math.sin(o+Math.PI/2),u=l/Math.sin(h+Math.PI/2),c=f(c)?c:0,u=f(u)?u:0,this.drawingArea=d-(u+c)/2,this.setCenterPoint(u,c)},setCenterPoint:function(t,i){var e=this.width-i-this.drawingArea,s=t+this.drawingArea;this.xCenter=(s+e)/2,this.yCenter=this.height/2},getIndexAngle:function(t){var i=2*Math.PI/this.valuesCount;return t*i-Math.PI/2},getPointPosition:function(t,i){var e=this.getIndexAngle(t);return{x:Math.cos(e)*i+this.xCenter,y:Math.sin(e)*i+this.yCenter}},draw:function(){if(this.display){var t=this.ctx;if(n(this.yLabels,function(i,e){if(e>0){var s,n=e*(this.drawingArea/this.steps),o=this.yCenter-n;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,n,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a<this.valuesCount;a++)s=this.getPointPosition(a,this.calculateCenterOffset(this.min+e*this.stepValue)),0===a?t.moveTo(s.x,s.y):t.lineTo(s.x,s.y);t.closePath(),t.stroke()}if(this.showLabels){if(t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.showLabelBackdrop){var h=t.measureText(i).width;t.fillStyle=this.backdropColor,t.fillRect(this.xCenter-h/2-this.backdropPaddingX,o-this.fontSize/2-this.backdropPaddingY,h+2*this.backdropPaddingX,this.fontSize+2*this.backdropPaddingY)}t.textAlign=\"center\",t.textBaseline=\"middle\",t.fillStyle=this.fontColor,t.fillText(i,this.xCenter,o)}}},this),!this.lineArc){t.lineWidth=this.angleLineWidth,t.strokeStyle=this.angleLineColor;for(var i=this.valuesCount-1;i>=0;i--){if(this.angleLineWidth>0){var e=this.getPointPosition(i,this.calculateCenterOffset(this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(e.x,e.y),t.stroke(),t.closePath()}var s=this.getPointPosition(i,this.calculateCenterOffset(this.max)+5);t.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var o=this.labels.length,a=this.labels.length/2,h=a/2,l=h>i||i>o-h,r=i===h||i===o-h;t.textAlign=0===i?\"center\":i===a?\"center\":a>i?\"left\":\"right\",t.textBaseline=r?\"middle\":l?\"bottom\":\"top\",t.fillText(this.labels[i],s.x,s.y)}}}}}),s.addEvent(window,\"resize\",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){n(e.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),p?define(function(){return e}):\"object\"==typeof module&&module.exports&&(module.exports=e),t.Chart=e,e.noConflict=function(){return t.Chart=i,e}}).call(this),function(){\"use strict\";var t=this,i=t.Chart,e=i.helpers,s={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:\"rgba(0,0,0,.05)\",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:\"Bar\",defaults:s,initialize:function(t){var s=this.options;this.ScaleClass=i.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,i,e){var n=this.calculateBaseWidth(),o=this.calculateX(e)-n/2,a=this.calculateBarWidth(t);return o+a*i+i*s.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*s.barValueSpacing},calculateBarWidth:function(t){var i=this.calculateBaseWidth()-(t-1)*s.barDatasetSpacing;return i/t}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i=\"mouseout\"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore([\"fillColor\",\"strokeColor\"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),this.BarClass=i.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,bars:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.bars.push(new this.BarClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.strokeColor,fillColor:i.fillColor,highlightFill:i.highlightFill||i.fillColor,highlightStroke:i.highlightStroke||i.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,i,s){e.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,s,i),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore([\"fillColor\",\"strokeColor\"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){e.each(this.datasets,function(i,s){e.each(i.bars,t,this,s)},this)},getBarsAtEvent:function(t){for(var i,s=[],n=e.getRelativePosition(t),o=function(t){s.push(t.bars[i])},a=0;a<this.datasets.length;a++)for(i=0;i<this.datasets[a].bars.length;i++)if(this.datasets[a].bars[i].inRange(n.x,n.y))return e.each(this.datasets,o),s;return s},buildScale:function(t){var i=this,s=function(){var t=[];return i.eachBars(function(i){t.push(i.value)}),t},n={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var i=e.calculateScaleRange(s(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,i)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:\"rgba(0,0,0,0)\",padding:this.options.showScale?0:this.options.barShowStroke?this.options.barStrokeWidth:0,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(n,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new this.ScaleClass(n)},addData:function(t,i){e.each(t,function(t,e){this.datasets[e].bars.push(new this.BarClass({value:t,label:i,x:this.scale.calculateBarX(this.datasets.length,e,this.scale.valuesCount+1),y:this.scale.endPoint,width:this.scale.calculateBarWidth(this.datasets.length),base:this.scale.endPoint,strokeColor:this.datasets[e].strokeColor,fillColor:this.datasets[e].fillColor}))\n},this),this.scale.addXLabel(i),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.bars.shift()},this),this.update()},reflow:function(){e.extend(this.BarClass.prototype,{y:this.scale.endPoint,base:this.scale.endPoint});var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var i=t||1;this.clear();this.chart.ctx;this.scale.draw(i),e.each(this.datasets,function(t,s){e.each(t.bars,function(t,e){t.hasValue()&&(t.base=this.scale.endPoint,t.transition({x:this.scale.calculateBarX(this.datasets.length,s,e),y:this.scale.calculateY(t.value),width:this.scale.calculateBarWidth(this.datasets.length)},i).draw())},this)},this)}})}.call(this),function(){\"use strict\";var t=this,i=t.Chart,e=i.helpers,s={segmentShowStroke:!0,segmentStrokeColor:\"#fff\",segmentStrokeWidth:2,percentageInnerCutout:50,animationSteps:100,animationEasing:\"easeOutBounce\",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:\"Doughnut\",defaults:s,initialize:function(t){this.segments=[],this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=i.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i=\"mouseout\"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore([\"fillColor\"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.calculateTotal(t),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),e||(this.reflow(),this.update())},calculateCircumference:function(t){return 2*Math.PI*(Math.abs(t)/this.total)},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),e.each(this.activeElements,function(t){t.restore([\"fillColor\"])}),e.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,e.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var i=t?t:1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},i),t.endAngle=t.startAngle+t.circumference,t.draw(),0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle)},this)}}),i.types.Doughnut.extend({name:\"Pie\",defaults:e.merge(s,{percentageInnerCutout:0})})}.call(this),function(){\"use strict\";var t=this,i=t.Chart,e=i.helpers,s={scaleShowGridLines:!0,scaleGridLineColor:\"rgba(0,0,0,.05)\",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,bezierCurve:!0,bezierCurveTension:.4,pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:\"Line\",defaults:s,initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)<Math.pow(this.radius+this.hitDetectionRadius,2)}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i=\"mouseout\"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore([\"fillColor\",\"strokeColor\"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this),this.buildScale(t.labels),this.eachPoints(function(t,i){e.extend(t,{x:this.scale.calculateX(i),y:this.scale.endPoint}),t.save()},this)},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore([\"fillColor\",\"strokeColor\"])}),this.eachPoints(function(t){t.save()}),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.datasets,function(t){e.each(t.points,function(t){t.inRange(s.x,s.y)&&i.push(t)})},this),i},buildScale:function(t){var s=this,n=function(){var t=[];return s.eachPoints(function(i){t.push(i.value)}),t},o={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var i=e.calculateScaleRange(n(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,i)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:\"rgba(0,0,0,0)\",padding:this.options.showScale?0:this.options.pointDotRadius+this.options.pointDotStrokeWidth,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(o,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new i.Scale(o)},addData:function(t,i){e.each(t,function(t,e){this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:this.scale.calculateX(this.scale.valuesCount+1),y:this.scale.endPoint,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.addXLabel(i),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.points.shift()},this),this.update()},reflow:function(){var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var i=t||1;this.clear();var s=this.chart.ctx,n=function(t){return null!==t.value},o=function(t,i,s){return e.findNextWhere(i,n,s)||t},a=function(t,i,s){return e.findPreviousWhere(i,n,s)||t};this.scale.draw(i),e.each(this.datasets,function(t){var h=e.where(t.points,n);e.each(t.points,function(t,e){t.hasValue()&&t.transition({y:this.scale.calculateY(t.value),x:this.scale.calculateX(e)},i)},this),this.options.bezierCurve&&e.each(h,function(t,i){var s=i>0&&i<h.length-1?this.options.bezierCurveTension:0;t.controlPoints=e.splineCurve(a(t,h,i),t,o(t,h,i),s),t.controlPoints.outer.y>this.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.y<this.scale.startPoint&&(t.controlPoints.outer.y=this.scale.startPoint),t.controlPoints.inner.y>this.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y<this.scale.startPoint&&(t.controlPoints.inner.y=this.scale.startPoint)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(h,function(t,i){if(0===i)s.moveTo(t.x,t.y);else if(this.options.bezierCurve){var e=a(t,h,i);s.bezierCurveTo(e.controlPoints.outer.x,e.controlPoints.outer.y,t.controlPoints.inner.x,t.controlPoints.inner.y,t.x,t.y)}else s.lineTo(t.x,t.y)},this),s.stroke(),this.options.datasetFill&&h.length>0&&(s.lineTo(h[h.length-1].x,this.scale.endPoint),s.lineTo(h[0].x,this.scale.endPoint),s.fillStyle=t.fillColor,s.closePath(),s.fill()),e.each(h,function(t){t.draw()})},this)}})}.call(this),function(){\"use strict\";var t=this,i=t.Chart,e=i.helpers,s={scaleShowLabelBackdrop:!0,scaleBackdropColor:\"rgba(255,255,255,0.75)\",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:\"#fff\",segmentStrokeWidth:2,animationSteps:100,animationEasing:\"easeOutBounce\",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:\"PolarArea\",defaults:s,initialize:function(t){this.segments=[],this.SegmentArc=i.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i=\"mouseout\"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore([\"fillColor\"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),e||(this.reflow(),this.update())},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var i=[];e.each(t,function(t){i.push(t.value)});var s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s,{size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),e.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),e.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),e.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var i=t||1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},i),t.endAngle=t.startAngle+t.circumference,0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle),t.draw()},this),this.scale.draw()}})}.call(this),function(){\"use strict\";var t=this,i=t.Chart,e=i.helpers;i.Type.extend({name:\"Radar\",defaults:{scaleShowLine:!0,angleShowLineOut:!0,scaleShowLabels:!1,scaleBeginAtZero:!0,angleLineColor:\"rgba(0,0,0,.1)\",angleLineWidth:1,pointLabelFontFamily:\"'Arial'\",pointLabelFontStyle:\"normal\",pointLabelFontSize:10,pointLabelFontColor:\"#666\",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'},initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i=\"mouseout\"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore([\"fillColor\",\"strokeColor\"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){var o;this.scale.animation||(o=this.scale.getPointPosition(n,this.scale.calculateCenterOffset(e))),s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=e.getRelativePosition(t),s=e.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},i),n=2*Math.PI/this.scale.valuesCount,o=Math.round((s.angle-1.5*Math.PI)/n),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),s.distance<=this.scale.drawingArea&&e.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var i=function(){var i=[];return e.each(t,function(t){t.data?i=i.concat(t.data):e.each(t.points,function(t){i.push(t.value)})}),i}(),s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s)},addData:function(t,i){this.scale.valuesCount++,e.each(t,function(t,e){var s=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:s.x,y:s.y,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.labels.push(i),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),e.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var i=t||1,s=this.chart.ctx;this.clear(),this.scale.draw(),e.each(this.datasets,function(t){e.each(t.points,function(t,e){t.hasValue()&&t.transition(this.scale.getPointPosition(e,this.scale.calculateCenterOffset(t.value)),i)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(t.points,function(t,i){0===i?s.moveTo(t.x,t.y):s.lineTo(t.x,t.y)},this),s.closePath(),s.stroke(),s.fillStyle=t.fillColor,s.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this);\n//Bootstrap.js\n+function(a){\"use strict\";function c(c,d){return this.each(function(){var e=a(this),f=e.data(\"bs.modal\"),g=a.extend({},b.DEFAULTS,e.data(),\"object\"==typeof c&&c);f||e.data(\"bs.modal\",f=new b(this,g)),\"string\"==typeof c?f[c](d):g.show&&f.show(d)})}var b=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(\".modal-dialog\"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(\".modal-content\").load(this.options.remote,a.proxy(function(){this.$element.trigger(\"loaded.bs.modal\")},this))};b.VERSION=\"3.3.4\",b.TRANSITION_DURATION=300,b.BACKDROP_TRANSITION_DURATION=150,b.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},b.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},b.prototype.show=function(c){var d=this,e=a.Event(\"show.bs.modal\",{relatedTarget:c});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass(\"modal-open\"),this.escape(),this.resize(),this.$element.on(\"click.dismiss.bs.modal\",'[data-dismiss=\"modal\"]',a.proxy(this.hide,this)),this.$dialog.on(\"mousedown.dismiss.bs.modal\",function(){d.$element.one(\"mouseup.dismiss.bs.modal\",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass(\"fade\");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass(\"in\").attr(\"aria-hidden\",!1),d.enforceFocus();var f=a.Event(\"shown.bs.modal\",{relatedTarget:c});e?d.$dialog.one(\"bsTransitionEnd\",function(){d.$element.trigger(\"focus\").trigger(f)}).emulateTransitionEnd(b.TRANSITION_DURATION):d.$element.trigger(\"focus\").trigger(f)}))},b.prototype.hide=function(c){c&&c.preventDefault(),c=a.Event(\"hide.bs.modal\"),this.$element.trigger(c),this.isShown&&!c.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off(\"focusin.bs.modal\"),this.$element.removeClass(\"in\").attr(\"aria-hidden\",!0).off(\"click.dismiss.bs.modal\").off(\"mouseup.dismiss.bs.modal\"),this.$dialog.off(\"mousedown.dismiss.bs.modal\"),a.support.transition&&this.$element.hasClass(\"fade\")?this.$element.one(\"bsTransitionEnd\",a.proxy(this.hideModal,this)).emulateTransitionEnd(b.TRANSITION_DURATION):this.hideModal())},b.prototype.enforceFocus=function(){a(document).off(\"focusin.bs.modal\").on(\"focusin.bs.modal\",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger(\"focus\")},this))},b.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on(\"keydown.dismiss.bs.modal\",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off(\"keydown.dismiss.bs.modal\")},b.prototype.resize=function(){this.isShown?a(window).on(\"resize.bs.modal\",a.proxy(this.handleUpdate,this)):a(window).off(\"resize.bs.modal\")},b.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass(\"modal-open\"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger(\"hidden.bs.modal\")})},b.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},b.prototype.backdrop=function(c){var d=this,e=this.$element.hasClass(\"fade\")?\"fade\":\"\";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a('<div class=\"modal-backdrop '+e+'\" />').appendTo(this.$body),this.$element.on(\"click.dismiss.bs.modal\",a.proxy(function(a){return this.ignoreBackdropClick?(this.ignoreBackdropClick=!1,void 0):(a.target===a.currentTarget&&(\"static\"==this.options.backdrop?this.$element[0].focus():this.hide()),void 0)},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass(\"in\"),!c)return;f?this.$backdrop.one(\"bsTransitionEnd\",c).emulateTransitionEnd(b.BACKDROP_TRANSITION_DURATION):c()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass(\"in\");var g=function(){d.removeBackdrop(),c&&c()};a.support.transition&&this.$element.hasClass(\"fade\")?this.$backdrop.one(\"bsTransitionEnd\",g).emulateTransitionEnd(b.BACKDROP_TRANSITION_DURATION):g()}else c&&c()},b.prototype.handleUpdate=function(){this.adjustDialog()},b.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:\"\",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:\"\"})},b.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:\"\",paddingRight:\"\"})},b.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},b.prototype.setScrollbar=function(){var a=parseInt(this.$body.css(\"padding-right\")||0,10);this.originalBodyPad=document.body.style.paddingRight||\"\",this.bodyIsOverflowing&&this.$body.css(\"padding-right\",a+this.scrollbarWidth)},b.prototype.resetScrollbar=function(){this.$body.css(\"padding-right\",this.originalBodyPad)},b.prototype.measureScrollbar=function(){var a=document.createElement(\"div\");a.className=\"modal-scrollbar-measure\",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=c,a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on(\"click.bs.modal.data-api\",'[data-toggle=\"modal\"]',function(b){var d=a(this),e=d.attr(\"href\"),f=a(d.attr(\"data-target\")||e&&e.replace(/.*(?=#[^\\s]+$)/,\"\")),g=f.data(\"bs.modal\")?\"toggle\":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is(\"a\")&&b.preventDefault(),f.one(\"show.bs.modal\",function(a){a.isDefaultPrevented()||f.one(\"hidden.bs.modal\",function(){d.is(\":visible\")&&d.trigger(\"focus\")})}),c.call(f,g,this)})}(Zepto);"
  },
  {
    "path": "app/http/html/speed_test.html",
    "content": "<html>\n\n<head>\n  <title>Smart Relay</title>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <link rel=\"stylesheet\" href=\"bootstrap.css\"> \n  </head>\n  <body>\n  \t<nav class=\"navbar-inverse navbar-default\">\n\t  <div class=\"container-fluid\">\n\t    <div class=\"navbar-header\">\t     \n\t      <a class=\"navbar-brand\" href=\"#\"></a>\n\t    </div>\n\t    <div class=\"collapse navbar-collapse\" id=\"bs-example-navbar-collapse-1\">\n                    <ul class=\"nav navbar-nav\">\n                     <li ><a href=\"/\">Config</a></li>\n                     <li class=\"active\"><a href=\"/speed-test\">Speed Test</a></li>\n                     <li ><a href=\"/cats\">Cats</a></li>                     \n                    </ul>                  \n                   \n        </div>\n\t  </div>\n\t</nav>\n\t\n\t<div class=\"container\">\n\t\t\n\t\t<h1>Smart Relay</h1>\n\t\t<div class=\"page-header\">\n\t\t\t\t<h3>Speed Test</h3>\n\t\t</div>\n\t\t<h2 id='status'>Connecting...</h2>\n        <div class=\"row\">\n\t        <div class=\"col-lg-1\">\n\t        \t<div class=\"form-group\">\n\t                  <label class=\"control-label\">Bytes / packet</label>\n\t                  <div class=\"input-group\" id=\"byte-count\">                   \t\t\t  \n\t\t\t\t\t\t  <a href=\"#\" class=\"list-group-item active\" data-rate=\"32\">32</a>\n\t\t\t\t\t\t  <a href=\"#\" class=\"list-group-item\"  data-rate=\"64\">64</a>\n\t\t\t\t\t\t  <a href=\"#\" class=\"list-group-item\"  data-rate=\"128\">128</a>\n\t\t\t\t\t\t  <a href=\"#\" class=\"list-group-item\"  data-rate=\"256\">256</a>\n\t\t\t\t\t\t  <a href=\"#\" class=\"list-group-item\"  data-rate=\"512\">512</a>\n\t\t\t\t\t\t  <a href=\"#\" class=\"list-group-item\"  data-rate=\"1024\">1024</a>\n\t\t\t\t\t  </div>\n\t            </div>\n\t                \n\t        </div>\n\t\t\t <div class=\"col-lg-10\" >\n\t\t\t \t <canvas id=\"speed-chart\" height=\"300\"></canvas>\n\t\t\t </div>\n\t\t </div>\t\t\n\t\t <div class=\"row\" style=\"margin-bottom:30px\">\n\t\t \t<a href=\"#\" class=\"btn btn-success\"  id=\"start-stop-button\">START</a>\n\t\t </div>\n\t\t \n\n\t</div>\n\n\t<script src=\"lib.js\" type=\"text/javascript\"></script>\t\n\n\t<script type=\"text/javascript\">\n\t\t\n\t\t$(function(){\n\n\t\t\tvar ws_connected=0;\n\t\t\tvar running =0;\n\n\t\t\t// Get the context of the canvas element we want to select\n\t\t\tvar canvas = $('#speed-chart');\n\t\t\tcanvas.attr('width',canvas.parent().width());\n\n\t\t\tvar ctx = document.getElementById(\"speed-chart\").getContext(\"2d\");\n\t\t\t\n\t\t\tvar options = {animation :false} ;\n\n\t\t\tvar chartData = {\n\t\t    labels: [],\n\t\t    datasets: [\n\t\t\t\t        {\n\t\t\t\t            label: \"Speed\",\n\t\t\t\t            fillColor: \"rgba(220,220,220,0.2)\",\n\t\t\t\t            strokeColor: \"rgba(220,220,220,1)\",\n\t\t\t\t            pointColor: \"rgba(220,220,220,1)\",\n\t\t\t\t            pointStrokeColor: \"#fff\",\n\t\t\t\t            pointHighlightFill: \"#fff\",\n\t\t\t\t            pointHighlightStroke: \"rgba(220,220,220,1)\",\n\t\t\t\t            data: []\n\t\t\t\t        }\n\t\t    \t\t]\n\t\t\t};\n\n\t\t\t//init data\t\t\t\n\n\t\t\tvar lineChart = new Chart(ctx).Line(chartData, options);\n\n\t\t\tvar date = new Date();\n\t\t\tvar time = date.getTime();\n\n\t\t\tvar received = 0;\n\t\t\tvar count = 0;\t\t\t\n\n\t\t\tfunction updateData(){\n\t\t\t\tif(running){\n\t\t\t\t\t//shift data\n\n\t\t\t        //push new\n\t\t\t        lineChart.addData([received+0],count.toString());\n\n\t\t\t        if(count >= 60)\n\t\t\t        \tlineChart.removeData();\n\n\t\t\t        //render update\t\t\t        \n\t\t\t        received=0;\n\t\t\t        count++;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}\n\n\t\t\tsetInterval(updateData,1000); //update every sec\n\n\t\t\tvar ws=null;\n\t\t\tfunction connect(){\n\n\t\t\t\tvar newWs = new WebSocket(\"ws://smart.relay.com:8088\");\n\t\t\t\tif (newWs.readyState === 1) {\n\t\t\t\t\t$('#status').text('Websocket connected!');\n\t\t\t        ws_connected=1;\n\t\t\t        received=0;\n\t\t\t\t}\n\t\t\t\tnewWs.onopen = function()\n\t\t\t     {\n\t\t\t        $('#status').text('Websocket connected!');\n\t\t\t        ws_connected=1;\n\t\t\t        received=0;\n\t\t\t     };\n\t\t\t     newWs.onmessage = function (evt) \n\t\t\t     { \n\t\t\t        //update data\t\t\t\t       \n\t\t\t        received+=evt.data.size;\n\t\t\t     };\n\t\t\t     newWs.onclose = function()\n\t\t\t     { \n\t\t\t     \tws_connected=0;\n\t\t\t         $('#status').text('Websocket lost connection, trying again');\n\t\t\t         running=0;\n\t\t\t\t\t$('#start-stop-button').text('START');\n\t\t\t         setTimeout(function(){connect();},1000);\n\t\t\t     };\n\n\t\t\t     ws=newWs;\n\n\t\t\t}\t\n\t\t\tconnect();\n\t\t\t\n\t\t\t$(document).on('click','#byte-count a', function(e){\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\n\t\t\t\t//clear active\n\t\t\t\t$('#byte-count a').removeClass('active');\n\t\t\t\t$(this).addClass('active');\n\n\t\t\t\tif(running){\n\t\t\t\t\tvar rate = $(this).data('rate');\n\t\t\t\t\tws.send('stream start '+rate);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t$(document).on('click','#start-stop-button', function(e){\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\n\t\t\t\tif(!running){\n\t\t\t\t\tvar rate = $('#byte-count a.active').data('rate');\n\n\t\t\t\t\t//init data\n\t\t\t\t\tchartData.datasets[0].data=[];\n\t\t\t\t\tcount=0;\n\n\t\t\t\t\tws.send('stream start '+rate);\n\t\t\t\t\t$('#start-stop-button').text('STOP');\n\t\t\t\t\trunning=1;\n\t\t\t\t}\n\t\t\t\telse{\n\t\t\t\t\tws.send(\"stream stop\");\n\t\t\t\t\trunning=0;\n\t\t\t\t\t$('#start-stop-button').text('START');\n\t\t\t\t}\t\t\t\n\n\n\n\t\t\t});\n\n\t\t});\n\t</script>\n\n  </body>\n </html>"
  },
  {
    "path": "app/http/http.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __HTTP_H\n#define __HTTP_H\n\n#define HTTP_BUFFER_SIZE 1460 // Let's keep it close the TCP MTU (maximum transmit unit) ( 1460 on this lwip ) \n \t\t\t\t\t\t\t  //so we will send a whole packet per time\n#define MAX_HEADERS 10\n#define URL_MAX_SIZE 256\n\n\n#include \"http_parser.h\"\n#include \"espconn.h\"\n#include \"lwip/ip_addr.h\"\n\ntypedef struct http_connection http_connection;\ntypedef int (*http_callback)(http_connection *c);  //callback function\ntypedef int (*cgi_execute_function)(http_connection *c); //cgi execute function\n\ntypedef struct {\n\tconst char * key;\n\tchar * value;\n\tuint8_t save;\n} header;\n\ntypedef struct {\n\t\tuint8_t *buffer;\n\t\tuint8_t *bufferPos;\n\t\theader headers[MAX_HEADERS];\n} http_buffer;\n\ntypedef struct {\t\n\t\tcgi_execute_function execute;\t\t\n\n\t\thttp_callback function;\n\n\t\tvoid *data;\n\t\tconst void *argument;\n\t\tuint8_t done;\n\n\t\tuint32_t flags;\n\n} cgi_struct;\n\nstruct http_connection{\n\n\tuint8_t type;\n\n\tstruct espconn *espConnection;\n\n\tstruct espconn client_connection;\n\tesp_tcp client_tcp;\n\tip_addr_t host_ip;\n\tos_timer_t timeout_timer;\n\tenum http_method method;\n\tchar * request_body;\n\n\tstruct http_parser parser;\n\tstruct http_parser_settings parser_settings;\n\t\n\tuint8_t state;\n\n\tchar url[URL_MAX_SIZE];\n\tstruct http_parser_url url_parsed;\n\n\t//headers\n\theader headers[MAX_HEADERS];\t\n\n\t//body\n\tstruct {\n\t\tuint8_t save;\n\t\tchar *data;\n\t\tsize_t len;\n\t} body;\t\n\n\tcgi_struct cgi;\n\n\thttp_buffer output;\n\n\t//websocket related\n\tuint8_t handshake_ok;\n\n\t\n\n\tvoid *reverse;\n};\n\n\n\n#endif"
  },
  {
    "path": "app/http/http_client.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"osapi.h\"\n#include \"c_string.h\"\n#include \"user_interface.h\"\n#include \"mem.h\"\n#include \"espconn.h\"\n#include \"platform.h\"\n#include \"user_config.h\"\n#include \"lwip/dns.h\"\n\n#include \"http.h\"\n#include \"http_client.h\"\n#include \"http_parser.h\"\n#include \"http_helper.h\"\n#include \"http_process.h\"\n\n\nvoid ICACHE_FLASH_ATTR http_client_request_execute(http_connection *c)\n{\n\tNODE_DBG(\"http_client_request_execute \");\n\n\tif(c->state==HTTP_CLIENT_CONNECT_OK){\n\t\t//we should send request headers\n\n\t\tchar * path = http_url_get_path(c);\n\t\tchar * query = http_url_get_query(c);\n\n\t\tchar * requestPath;\n\t\tif(query!=NULL){\n\t\t\trequestPath = (char *)os_zalloc(strlen(path)+strlen(query)+2);\n\t\t\tos_strcpy(requestPath,path);\n\t\t\tos_strcat(requestPath,\"?\");\n\t\t\tos_strcat(requestPath,query);\n\t\t}\n\t\telse{\n\t\t\trequestPath = (char *)os_zalloc(strlen(path)+1);\n\t\t\tos_strcpy(requestPath,path);\n\t\t}\t\t\t\n\n\t\tif(path==NULL)\n\t\t\tpath = \"/\";\n\n\t\thttp_SET_HEADER(c,HTTP_HOST,http_url_get_host(c));\n\t\thttp_SET_HEADER(c,HTTP_USER_AGENT,HTTP_DEFAULT_SERVER);\n\n\t\tif(c->method==HTTP_GET){\n\t\t\thttp_request_GET(c,requestPath);\n\t\t\tos_free(requestPath);\n\t\t}\n\t\telse if(c->method==HTTP_POST){\n\t\t\thttp_request_POST(c,requestPath);\n\t\t\tos_free(requestPath);\n\t\t}\n\t\telse\n\t\t\treturn;\n\t\t\n\t\tc->state=HTTP_CLIENT_REQUEST_HEADERS_SENT;\n\n\t\thttp_transmit(c); // send request\n\t}\n\telse if(c->state==HTTP_CLIENT_REQUEST_HEADERS_SENT){\n\t\t//we can now send the body\n\n\t\tif(c->request_body!=NULL){\n\t\t\t//body is already here, send\n\t\t\tint bodyLen = os_strlen(c->request_body);\n\t\t\tif(bodyLen>=HTTP_BUFFER_SIZE){\n\t\t\t\thttp_nwrite(c,c->request_body,HTTP_BUFFER_SIZE);\n\t\t\t\tc->request_body+=HTTP_BUFFER_SIZE;\n\t\t\t}\n\t\t\telse\n\t\t\t\thttp_write(c,c->request_body);\n\n\t\t\thttp_transmit(c);\t\t\t\n\t\t}\n\t\telse{\n\t\t\t//callback so body can be sent elsewhere\n\t\t\thttp_execute_cgi(c);\t\n\t\t}\n\n\t\tc->state=HTTP_CLIENT_REQUEST_BODY_SENT;\n\n\t}\n\t\n\n}\n\n\nvoid ICACHE_FLASH_ATTR http_client_dns_found_cb(const char *name, ip_addr_t *ipaddr, void *arg){\n\n\tNODE_DBG(\"http_client_dns_callback conn=%p\",arg);\n\n\thttp_connection *c = (http_connection*)arg;\n\n\tif(c==NULL)\n\t\treturn;\n\n\tos_timer_disarm(&c->timeout_timer);\n\tc->host_ip.addr=ipaddr->addr;\n\n\tif(name!=NULL && ipaddr!=NULL){\n\n\t\t#ifdef DEVELOP_VERSION\n\t\tNODE_DBG(\"http_client_dns_callback: %s %d.%d.%d.%d\",\n\t\t\tname,\n\t\t\tip4_addr1(&ipaddr->addr),\n\t\t\tip4_addr2(&ipaddr->addr),\n\t\t\tip4_addr3(&ipaddr->addr),\n\t\t\tip4_addr4(&ipaddr->addr));\n\t\t#endif\t\n\t\t\n\t\t//set ip on tcp\n\t\tc->espConnection->proto.tcp->remote_ip[0]=ip4_addr1(&ipaddr->addr);\n\t\tc->espConnection->proto.tcp->remote_ip[1]=ip4_addr2(&ipaddr->addr);\n\t\tc->espConnection->proto.tcp->remote_ip[2]=ip4_addr3(&ipaddr->addr);\n\t\tc->espConnection->proto.tcp->remote_ip[3]=ip4_addr4(&ipaddr->addr);\n\n\t\t//DNS found\n\t\tc->state = HTTP_CLIENT_DNS_FOUND;\n\t}\n\telse{\n\t\t//DNS found\n\t\tc->state = HTTP_CLIENT_DNS_NOT_FOUND;\n\t}\n\n\thttp_execute_cgi(c);\t\n\t\n}\n\nvoid ICACHE_FLASH_ATTR http_client_dns_timeout(void *arg){\n\tNODE_DBG(\"http_client_dns_timeout\");\n\thttp_connection *c = (http_connection*)arg;\n\t\n\t// put null so if dns query response arrives, it wont trigger \n\t// execute again\n\tc->espConnection->reverse=NULL;\n\n\tc->state = HTTP_CLIENT_DNS_NOT_FOUND;\n\thttp_execute_cgi(c);\n}\n\nvoid ICACHE_FLASH_ATTR http_client_dns(http_connection *c){\n\n\tchar * host = http_url_get_host(c);\n\tNODE_DBG(\"http_client_dns: %s\",host);\n\t\n\tos_memset(&c->host_ip,0,sizeof(ip_addr_t));\n\tdns_gethostbyname(host, &c->host_ip, &http_client_dns_found_cb,(void*)c);\n\n    os_timer_disarm(&c->timeout_timer);\n    os_timer_setfn(&c->timeout_timer, (os_timer_func_t *)http_client_dns_timeout, c);\n    os_timer_arm(&c->timeout_timer, 1000, 0);\n\n}\n\nvoid ICACHE_FLASH_ATTR http_client_connect_callback(void *arg) {\n\n\tstruct espconn *conn=arg;\n\n\tNODE_DBG(\"http_client_connect_callback: %d\",conn->state==ESPCONN_CONNECT?1:0);\n\n\thttp_connection *c = (http_connection *)conn->reverse;\n\n\tif(conn->state==ESPCONN_CONNECT)\n\t\tc->state=HTTP_CLIENT_CONNECT_OK;\t\n\telse\n\t\tc->state=HTTP_CLIENT_CONNECT_FAIL;\n\n\thttp_execute_cgi(c);\n\n}\n\nint ICACHE_FLASH_ATTR http_client_cgi_execute(http_connection *c){\n\n\tif(c->cgi.function==NULL)\n\t\treturn 0;\n\n\tint ret = c->cgi.function(c);\n\n\tif(c->state==HTTP_CLIENT_DNS_NOT_FOUND || (ret== HTTP_CLIENT_CGI_DONE && c->state==HTTP_CLIENT_DNS_FOUND)){\n\t\t//this was a dns request only\n\t\tNODE_DBG(\"Client conn %p done after DNS\",c);\n\t\thttp_process_free_connection(c);\n\t\treturn 0;\n\t}\n\telse if(ret== HTTP_CLIENT_CGI_DONE){\n\t\t//abort\n\t\tespconn_disconnect(c->espConnection);\n\t\thttp_process_free_connection(c);\n\t\treturn 0;\n\t}\n\n\tif(c->state==HTTP_CLIENT_DNS_FOUND){\t\t\n\t\t//connect\n\t\tespconn_connect(c->espConnection);\t\t\n\t}\n\tif(c->state==HTTP_CLIENT_CONNECT_OK){\n\t\t//we are ready to make the request\n\t\thttp_client_request_execute(c);\n\t}\n\tif(c->state==HTTP_CLIENT_CONNECT_FAIL){\n\t\t//free\n\t\tespconn_disconnect(c->espConnection);\n\t\thttp_process_free_connection(c);\t\t\n\t}\n\n}\n\nhttp_connection * ICACHE_FLASH_ATTR http_client_new(http_callback callback){\n\n\thttp_connection * client = http_new_connection(0,NULL);\n\n\tif(client==NULL)\n\t\treturn NULL;\n\t\n\tclient->cgi.execute=http_client_cgi_execute;\n\tclient->cgi.function = callback;\n\n\tespconn_regist_connectcb(client->espConnection, http_client_connect_callback);\t\n\n\treturn client;\n}\n\nint ICACHE_FLASH_ATTR http_client_open_url(http_connection *c,char *url){\n\t\n\tNODE_DBG(\"http_client_open_url: %s\",url);\n\n\tos_strcpy(c->url,url);\n\thttp_parse_url(c);\n\t\t\n\t//set port\n\tif(c->url_parsed.port>0)\n\t\tc->client_connection.proto.tcp->remote_port=c->url_parsed.port;\t\t\n\telse\t\n\t\tc->client_connection.proto.tcp->remote_port=80;\n\n\thttp_client_dns(c);\n\n\treturn 1;\n}\n\nint ICACHE_FLASH_ATTR http_client_GET(http_connection *c,char *url){\n\tc->method=HTTP_GET;\n\treturn http_client_open_url(c,url);\n}\n\n\n\n\n"
  },
  {
    "path": "app/http/http_client.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __HTTP_CLIENT_H\n#define __HTTP_CLIENT_H\n\n\n\nhttp_connection * ICACHE_FLASH_ATTR http_client_new(http_callback callback);\nint ICACHE_FLASH_ATTR http_client_open_url(http_connection *c,char *url);\n\n#endif"
  },
  {
    "path": "app/http/http_helper.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"c_types.h\"\n#include \"user_interface.h\"\n#include \"espconn.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"c_stdio.h\"\n#include \"user_config.h\"\n#include \"espconn.h\"\n\n#include \"http.h\"\n#include \"http_parser.h\"\n#include \"http_server.h\"\n#include \"http_process.h\"\n#include \"http_helper.h\"\n\n#include \"json/cJson.h\"\n\n//Struct to keep extension->mime data in\ntypedef struct {\n\tconst char *ext;\n\tconst char *mimetype;\n} MimeMap;////The mappings from file extensions to mime types. If you need an extra mime type,\n//add it here.\nstatic const MimeMap mimeTypes[]={\n\t{\"htm\", \"text/htm\"},\n\t{\"html\", \"text/html\"},\n\t{\"css\", \"text/css\"},\n\t{\"js\", \"text/javascript\"},\n\t{\"txt\", \"text/plain\"},\n\t{\"jpg\", \"image/jpeg\"},\n\t{\"jpeg\", \"image/jpeg\"},\n\t{\"png\", \"image/png\"},\n\t{\"json\",\"application/json\"},\n\t{\"svg\",\"image/svg+xml\"},\n\t{NULL, \"text/html\"}, //default value\n};\n\n\n\n\n\nint ICACHE_FLASH_ATTR http_reset_buffer(http_connection *c){\n\n\t//reset buffer\n\tos_memset(c->output.buffer,0,HTTP_BUFFER_SIZE);\n\tc->output.bufferPos = c->output.buffer;\n\n\t\n\t\n\treturn 1;\n}\n\nint ICACHE_FLASH_ATTR http_write_json(http_connection *c,cJSON *root){\n\n\tchar * json_string;\n\tjson_string = cJSON_Print(root);\n\n\tint ret = http_write(c,json_string);\n\tos_free(json_string);\n\treturn ret;\n\n}\n\n\nint ICACHE_FLASH_ATTR http_end_line(http_connection *c){\n\treturn http_write(c,\"\\r\\n\");\n}\n\n\nint ICACHE_FLASH_ATTR http_SET_HEADER(http_connection *c,const char * header,const char * value){\n\n\tNODE_DBG(\"Setting header: %s : %s\",header,value);\n\n\tint j=0;\n\twhile(c->output.headers[j].key!=NULL && j< MAX_HEADERS){\n\n\t\tif(os_strcmp(c->output.headers[j].key,header)==0){\n\t\t\t//header already on the list, overwrite\n\t\t\tif(c->output.headers[j].value!=NULL){\t\t\t\t\n\t\t\t\tos_free(c->output.headers[j].value);\t\t\t\t\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tj++;\n\t}\n\tif(j==MAX_HEADERS) return 0;\n\n\tc->output.headers[j].key=header;\n\tc->output.headers[j].value=(char *) os_malloc(strlen(value)+1);\n\n\tif(c->output.headers[j].value==NULL){\n\t\tNODE_DBG(\"Failed to alloc header memory\");\n\t\treturn 0;\n\t}\n\tos_strcpy(c->output.headers[j].value,value);\n\n\treturn 1;\n}\n\nint ICACHE_FLASH_ATTR http_SET_CONTENT_LENGTH(http_connection *c,int len){\n\n\tchar buff[10];\n\tos_sprintf(buff,\"%d\",len);\n\treturn http_SET_HEADER(c,HTTP_CONTENT_LENGTH,buff);\n\n}\n\nint ICACHE_FLASH_ATTR http_HEADER(http_connection *c,const char *header,const char *value){\n\t\n\tNODE_DBG(\"Writing  header: %s : %s\",header,value);\n\n\treturn http_write(c,header)\n\t&& http_write(c,\": \")\n\t&& http_write(c,value)\n\t&& http_end_line(c);\n\n}\n\nint ICACHE_FLASH_ATTR http_end_headers(http_connection *c){\n\n\n\t//write cached headers\n\tint j=0;\n\twhile(j< MAX_HEADERS){\n\n\t\tif(c->output.headers[j].key!=NULL){\n\t\t\t//write header\n\t\t\thttp_HEADER(c,c->output.headers[j].key,c->output.headers[j].value);\n\n\t\t\t//free header\n\t\t\tos_free(c->output.headers[j].value);\n\t\t\tc->output.headers[j].value=NULL;\n\t\t\tc->output.headers[j].key=NULL;\n\t\t}\t\n\n\t\tj++;\n\t}\n\n\t//write final empty line\n\treturn http_end_line(c);\n}\n\n\n\n//REQUEST\nint ICACHE_FLASH_ATTR http_request_start(http_connection *c,const char *method,const char *path){\n\t\n\thttp_reset_buffer(c);\n\n\tint ret = http_write(c,method)\n\t&& http_write(c,\" \")\n\t&& http_write(c,path)\n\t&& http_write(c,\" HTTP/1.0\")\n\t&& http_end_line(c)\n\t&& http_HEADER(c,HTTP_CONNECTION,\"Close\");\n\n\tNODE_DBG(\"Request: %s\",c->output.buffer);\n\n}\nint ICACHE_FLASH_ATTR http_request_GET(http_connection *c,const char *path){\n\treturn http_request_start(c,\"GET\",path) \n\t&& http_end_headers(c);\n}\nint ICACHE_FLASH_ATTR http_request_POST(http_connection *c,const char *path){\n\treturn http_request_start(c,\"POST\",path)\n\t&& http_end_headers(c);\n}\n\n//RESPONSE\nint ICACHE_FLASH_ATTR http_response_start(http_connection *c){\n\t\n\treturn http_write(c,\"HTTP/\") \n\t&& http_write(c,HTTP_VERSION)\n\t&& http_write(c,\" \");\n}\n\nint ICACHE_FLASH_ATTR http_response_STATUS(http_connection *c,const char * status){\n\n\treturn \n\thttp_response_start(c) && \n\thttp_write(c,status) && \n\thttp_end_line(c) &&\n\t//default headers\n\thttp_HEADER(c,HTTP_SERVER,HTTP_DEFAULT_SERVER) &&\n\thttp_HEADER(c,HTTP_CONNECTION,\"Close\");\n\n} \n\nint ICACHE_FLASH_ATTR http_response_OK(http_connection *c){\n\treturn http_response_STATUS(c,HTTP_OK) &&\n\thttp_end_headers(c);\n}\n\nint ICACHE_FLASH_ATTR http_response_BAD_REQUEST(http_connection *c){\n\treturn http_response_STATUS(c,HTTP_BAD_REQUEST) &&\n\thttp_end_headers(c);\n}\n\nint ICACHE_FLASH_ATTR http_response_NOT_FOUND(http_connection *c){\n\treturn \n\thttp_response_STATUS(c,HTTP_NOT_FOUND)&&\n\thttp_end_headers(c);\n}\n\nint ICACHE_FLASH_ATTR http_response_REDIRECT(http_connection *c,const char* destination){\n\treturn \t\n\thttp_response_STATUS(c,HTTP_REDIRECT) && \t\n\thttp_HEADER(c,HTTP_LOCATION,destination) &&\n\thttp_end_headers(c);\n}\n\n//ws\nint ICACHE_FLASH_ATTR http_websocket_HANDSHAKE(http_connection *c){\n\n\thttp_reset_buffer(c);\n\n\tint ret = http_write(c,\"HTTP/1.1 101 Switching Protocols\")\t\n\t&& http_end_line(c)\n\t&& http_end_headers(c);\t\t\n\treturn ret;\n}\n\n\n//Returns a static char* to a mime type for a given url to a file.\nconst char ICACHE_FLASH_ATTR *http_get_mime(char *url) {\n\tint i=0;\n\t//Go find the extension\n\tchar *ext=url+(strlen(url)-1);\n\twhile (ext!=url && *ext!='.') ext--;\n\tif (*ext=='.') ext++;\n\t\n\t//ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here...\n\twhile (mimeTypes[i].ext!=NULL && os_strcmp(ext, mimeTypes[i].ext)!=0) i++;\n\treturn mimeTypes[i].mimetype;\n}\n\n"
  },
  {
    "path": "app/http/http_helper.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef http_response_h\n#define http_response_h\n\n#include \"http_process.h\"\n\n#define HTTP_DEFAULT_SERVER \"Smart Relay 1.0\"\n#define HTTP_VERSION \"1.1\"\n\n#define HTTP_OK \"200 OK\"\n#define HTTP_MOVED \"301 Moved Permanently \"\n#define HTTP_REDIRECT \"302 Found\"\n#define HTTP_NOT_MODIFIED \"304 Not Modified\"\n#define HTTP_BAD_REQUEST \"400 Bad Request\"\n#define HTTP_NOT_FOUND \"404 Not Found\"\n#define HTTP_INTERNAL_ERROR \"500 Internal Server Error\"\n\n//headers\n#define HTTP_CONTENT_TYPE \"Content-Type\"\n#define HTTP_CONTENT_LENGTH \"Content-Length\"\n#define HTTP_CONNECTION \"Connection\"\n#define HTTP_CACHE_CONTROL \"Cache-Control\"\n#define HTTP_CONTENT_ENCODING \"Content-Encoding\"\n#define HTTP_LOCATION \"Location\"\n#define HTTP_HOST \"Host\"\n#define HTTP_ORIGIN \"Origin\"\n#define HTTP_SERVER \"Server\"\n#define HTTP_ACCESS_CONTROL_ALLOW_ORIGIN \"Access-Control-Allow-Origin\"\n#define HTTP_ACCESS_CONTROL_ALLOW_METHODS \"Access-Control-Allow-Methods\"\n#define HTTP_ACCESS_CONTROL_ALLOW_HEADERS \"Access-Control-Allow-Headers\"\n#define HTTP_ACCESS_CONTROL_REQUEST_HEADERS \"Access-Control-Request-Headers\"\n#define HTTP_ACCESS_CONTROL_REQUEST_METHOD \"Access-Control-Request-Method\"\n#define HTTP_USER_AGENT \"User-Agent\"\n//websocket headers\n#define HTTP_UPGRADE \"Upgrade\"\n#define HTTP_SEC_WEBSOCKET_KEY \"Sec-WebSocket-Key\"\n#define HTTP_SEC_WEBSOCKET_PROTOCOL \"Sec-WebSocket-Protocol\"\n#define HTTP_SEC_WEBSOCKET_VERSION \"Sec-WebSocket-Version\"\n#define HTTP_WEBSOCKET_ACCEPT \"Sec-WebSocket-Accept\"\n\n#define HTTP_CONNECTION_CLOSE \"Close\"\n\n#define JSON_CONTENT_TYPE \"application/json\"\n\n#define HTTP_DEFAULT_CACHE \"public, max-age=3600\"\n\n\n\n//request \nint ICACHE_FLASH_ATTR http_request_GET(http_connection *c,const char *path);\nint ICACHE_FLASH_ATTR http_request_POST(http_connection *c,const char *path);\n\n\n//response\nint ICACHE_FLASH_ATTR http_response_OK(http_connection *c);\nint ICACHE_FLASH_ATTR http_response_NOT_FOUND(http_connection *c);\nint ICACHE_FLASH_ATTR http_response_BAD_REQUEST(http_connection *c);\nint ICACHE_FLASH_ATTR http_response_REDIRECT(http_connection *c,const char* destination);\n\n//ws\nint ICACHE_FLASH_ATTR http_websocket_HANDSHAKE(http_connection *c);\n\n//common\nconst char ICACHE_FLASH_ATTR *http_get_mime(char *url);\nint ICACHE_FLASH_ATTR http_SET_HEADER(http_connection *c,const char *header,const char *value);\nint ICACHE_FLASH_ATTR http_end_headers(http_connection *c);\nint ICACHE_FLASH_ATTR http_reset_buffer(http_connection *c);\n\n\n\n#endif\n\n"
  },
  {
    "path": "app/http/http_parser.c",
    "content": "/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev\n *\n * Additional changes are licensed under the same terms as NGINX and\n * copyright Joyent, Inc. and other Node contributors. All rights reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * 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 DEALINGS\n * IN THE SOFTWARE.\n */\n#include \"http_parser.h\"\n\n#include \"c_stddef.h\"\n#include \"c_stdlib.h\"\n#include \"c_string.h\"\n#include \"c_limits.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"user_interface.h\"\n\n#define assert(X) //NOP\n\n#ifndef ULLONG_MAX\n# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */\n#endif\n\n#ifndef MIN\n# define MIN(a,b) ((a) < (b) ? (a) : (b))\n#endif\n\n#ifndef ARRAY_SIZE\n# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))\n#endif\n\n#ifndef BIT_AT\n# define BIT_AT(a, i)                                                \\\n  (!!((unsigned int) (a)[(unsigned int) (i) >> 3] &                  \\\n   (1 << ((unsigned int) (i) & 7))))\n#endif\n\n#ifndef ELEM_AT\n# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))\n#endif\n\n#define SET_ERRNO(e)                                                 \\\ndo {                                                                 \\\n  parser->http_errno = (e);                                          \\\n} while(0)\n\n#define CURRENT_STATE() p_state\n#define UPDATE_STATE(V) p_state = (enum state) (V);\n#define RETURN(V)                                                    \\\ndo {                                                                 \\\n  parser->state = CURRENT_STATE();                                   \\\n  return (V);                                                        \\\n} while (0);\n#define REEXECUTE()                                                  \\\n  goto reexecute;                                                    \\\n\n\n#define LIKELY(X) (X)\n#define UNLIKELY(X) (X)\n\n\n/* Run the notify callback FOR, returning ER if it fails */\n#define CALLBACK_NOTIFY_(FOR, ER)                                    \\\ndo {                                                                 \\\n  assert(HTTP_PARSER_ERRNO(parser) == HPE_OK);                       \\\n                                                                     \\\n  if (LIKELY(settings->on_##FOR)) {                                  \\\n    parser->state = CURRENT_STATE();                                 \\\n    if (UNLIKELY(0 != settings->on_##FOR(parser))) {                 \\\n      SET_ERRNO(HPE_CB_##FOR);                                       \\\n    }                                                                \\\n    UPDATE_STATE(parser->state);                                     \\\n                                                                     \\\n    /* We either errored above or got paused; get out */             \\\n    if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) {             \\\n      return (ER);                                                   \\\n    }                                                                \\\n  }                                                                  \\\n} while (0)\n\n/* Run the notify callback FOR and consume the current byte */\n#define CALLBACK_NOTIFY(FOR)            CALLBACK_NOTIFY_(FOR, p - data + 1)\n\n/* Run the notify callback FOR and don't consume the current byte */\n#define CALLBACK_NOTIFY_NOADVANCE(FOR)  CALLBACK_NOTIFY_(FOR, p - data)\n\n/* Run data callback FOR with LEN bytes, returning ER if it fails */\n#define CALLBACK_DATA_(FOR, LEN, ER)                                 \\\ndo {                                                                 \\\n  assert(HTTP_PARSER_ERRNO(parser) == HPE_OK);                       \\\n                                                                     \\\n  if (FOR##_mark) {                                                  \\\n    if (LIKELY(settings->on_##FOR)) {                                \\\n      parser->state = CURRENT_STATE();                               \\\n      if (UNLIKELY(0 !=                                              \\\n                   settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \\\n        SET_ERRNO(HPE_CB_##FOR);                                     \\\n      }                                                              \\\n      UPDATE_STATE(parser->state);                                   \\\n                                                                     \\\n      /* We either errored above or got paused; get out */           \\\n      if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) {           \\\n        return (ER);                                                 \\\n      }                                                              \\\n    }                                                                \\\n    FOR##_mark = NULL;                                               \\\n  }                                                                  \\\n} while (0)\n  \n/* Run the data callback FOR and consume the current byte */\n#define CALLBACK_DATA(FOR)                                           \\\n    CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)\n\n/* Run the data callback FOR and don't consume the current byte */\n#define CALLBACK_DATA_NOADVANCE(FOR)                                 \\\n    CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)\n\n/* Set the mark FOR; non-destructive if mark is already set */\n#define MARK(FOR)                                                    \\\ndo {                                                                 \\\n  if (!FOR##_mark) {                                                 \\\n    FOR##_mark = p;                                                  \\\n  }                                                                  \\\n} while (0)\n\n/* Don't allow the total size of the HTTP headers (including the status\n * line) to exceed HTTP_MAX_HEADER_SIZE.  This check is here to protect\n * embedders against denial-of-service attacks where the attacker feeds\n * us a never-ending header that the embedder keeps buffering.\n *\n * This check is arguably the responsibility of embedders but we're doing\n * it on the embedder's behalf because most won't bother and this way we\n * make the web a little safer.  HTTP_MAX_HEADER_SIZE is still far bigger\n * than any reasonable request or response so this should never affect\n * day-to-day operation.\n */\n#define COUNT_HEADER_SIZE(V)                                         \\\ndo {                                                                 \\\n  parser->nread += (V);                                              \\\n  if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) {            \\\n    SET_ERRNO(HPE_HEADER_OVERFLOW);                                  \\\n    goto error;                                                      \\\n  }                                                                  \\\n} while (0)\n\n\n#define PROXY_CONNECTION \"proxy-connection\"\n#define CONNECTION \"connection\"\n#define CONTENT_LENGTH \"content-length\"\n#define TRANSFER_ENCODING \"transfer-encoding\"\n#define UPGRADE \"upgrade\"\n#define CHUNKED \"chunked\"\n#define KEEP_ALIVE \"keep-alive\"\n#define CLOSE \"close\"\n\n\nstatic const char *method_strings[] =\n  {\n#define XX(num, name, string) #string,\n  HTTP_METHOD_MAP(XX)\n#undef XX\n  };\n\n\n/* Tokens as defined by rfc 2616. Also lowercases them.\n *        token       = 1*<any CHAR except CTLs or separators>\n *     separators     = \"(\" | \")\" | \"<\" | \">\" | \"@\"\n *                    | \",\" | \";\" | \":\" | \"\\\" | <\">\n *                    | \"/\" | \"[\" | \"]\" | \"?\" | \"=\"\n *                    | \"{\" | \"}\" | SP | HT\n */\nstatic const char tokens[256] = {\n/*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */\n        0,       0,       0,       0,       0,       0,       0,       0,\n/*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */\n        0,       0,       0,       0,       0,       0,       0,       0,\n/*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */\n        0,       0,       0,       0,       0,       0,       0,       0,\n/*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */\n        0,       0,       0,       0,       0,       0,       0,       0,\n/*  32 sp    33  !    34  \"    35  #    36  $    37  %    38  &    39  '  */\n        0,      '!',      0,      '#',     '$',     '%',     '&',    '\\'',\n/*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */\n        0,       0,      '*',     '+',      0,      '-',     '.',      0,\n/*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */\n       '0',     '1',     '2',     '3',     '4',     '5',     '6',     '7',\n/*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */\n       '8',     '9',      0,       0,       0,       0,       0,       0,\n/*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */\n        0,      'a',     'b',     'c',     'd',     'e',     'f',     'g',\n/*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */\n       'h',     'i',     'j',     'k',     'l',     'm',     'n',     'o',\n/*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */\n       'p',     'q',     'r',     's',     't',     'u',     'v',     'w',\n/*  88  X    89  Y    90  Z    91  [    92  \\    93  ]    94  ^    95  _  */\n       'x',     'y',     'z',      0,       0,       0,      '^',     '_',\n/*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */\n       '`',     'a',     'b',     'c',     'd',     'e',     'f',     'g',\n/* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */\n       'h',     'i',     'j',     'k',     'l',     'm',     'n',     'o',\n/* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */\n       'p',     'q',     'r',     's',     't',     'u',     'v',     'w',\n/* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */\n       'x',     'y',     'z',      0,      '|',      0,      '~',       0 };\n\n\nstatic const int8_t unhex[256] =\n  {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1\n  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1\n  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1\n  , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1\n  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1\n  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1\n  ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1\n  ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1\n  };\n\n\n#if HTTP_PARSER_STRICT\n# define T(v) 0\n#else\n# define T(v) v\n#endif\n\n\nstatic const uint8_t normal_url_char[32] = {\n/*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */\n        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,\n/*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */\n        0    | T(2)   |   0    |   0    | T(16)  |   0    |   0    |   0,\n/*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */\n        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,\n/*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */\n        0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,\n/*  32 sp    33  !    34  \"    35  #    36  $    37  %    38  &    39  '  */\n        0    |   2    |   4    |   0    |   16   |   32   |   64   |  128,\n/*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |   0,\n/*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/*  88  X    89  Y    90  Z    91  [    92  \\    93  ]    94  ^    95  _  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n/* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */\n        1    |   2    |   4    |   8    |   16   |   32   |   64   |   0, };\n\n#undef T\n\nenum state\n  { s_dead = 1 /* important that this is > 0 */\n\n  , s_start_req_or_res\n  , s_res_or_resp_H\n  , s_start_res\n  , s_res_H\n  , s_res_HT\n  , s_res_HTT\n  , s_res_HTTP\n  , s_res_first_http_major\n  , s_res_http_major\n  , s_res_first_http_minor\n  , s_res_http_minor\n  , s_res_first_status_code\n  , s_res_status_code\n  , s_res_status_start\n  , s_res_status\n  , s_res_line_almost_done\n\n  , s_start_req\n\n  , s_req_method\n  , s_req_spaces_before_url\n  , s_req_schema\n  , s_req_schema_slash\n  , s_req_schema_slash_slash\n  , s_req_server_start\n  , s_req_server\n  , s_req_server_with_at\n  , s_req_path\n  , s_req_query_string_start\n  , s_req_query_string\n  , s_req_fragment_start\n  , s_req_fragment\n  , s_req_http_start\n  , s_req_http_H\n  , s_req_http_HT\n  , s_req_http_HTT\n  , s_req_http_HTTP\n  , s_req_first_http_major\n  , s_req_http_major\n  , s_req_first_http_minor\n  , s_req_http_minor\n  , s_req_line_almost_done\n\n  , s_header_field_start\n  , s_header_field\n  , s_header_value_discard_ws\n  , s_header_value_discard_ws_almost_done\n  , s_header_value_discard_lws\n  , s_header_value_start\n  , s_header_value\n  , s_header_value_lws\n\n  , s_header_almost_done\n\n  , s_chunk_size_start\n  , s_chunk_size\n  , s_chunk_parameters\n  , s_chunk_size_almost_done\n\n  , s_headers_almost_done\n  , s_headers_done\n\n  /* Important: 's_headers_done' must be the last 'header' state. All\n   * states beyond this must be 'body' states. It is used for overflow\n   * checking. See the PARSING_HEADER() macro.\n   */\n\n  , s_chunk_data\n  , s_chunk_data_almost_done\n  , s_chunk_data_done\n\n  , s_body_identity\n  , s_body_identity_eof\n\n  , s_message_done\n  };\n\n\n#define PARSING_HEADER(state) (state <= s_headers_done)\n\n\nenum header_states\n  { h_general = 0\n  , h_C\n  , h_CO\n  , h_CON\n\n  , h_matching_connection\n  , h_matching_proxy_connection\n  , h_matching_content_length\n  , h_matching_transfer_encoding\n  , h_matching_upgrade\n\n  , h_connection\n  , h_content_length\n  , h_transfer_encoding\n  , h_upgrade\n\n  , h_matching_transfer_encoding_chunked\n  , h_matching_connection_token_start\n  , h_matching_connection_keep_alive\n  , h_matching_connection_close\n  , h_matching_connection_upgrade\n  , h_matching_connection_token\n\n  , h_transfer_encoding_chunked\n  , h_connection_keep_alive\n  , h_connection_close\n  , h_connection_upgrade\n  };\n\nenum http_host_state\n  {\n    s_http_host_dead = 1\n  , s_http_userinfo_start\n  , s_http_userinfo\n  , s_http_host_start\n  , s_http_host_v6_start\n  , s_http_host\n  , s_http_host_v6\n  , s_http_host_v6_end\n  , s_http_host_port_start\n  , s_http_host_port\n};\n\n/* Macros for character classes; depends on strict-mode  */\n#define CR                  '\\r'\n#define LF                  '\\n'\n#define LOWER(c)            (unsigned char)(c | 0x20)\n#define IS_ALPHA(c)         (LOWER(c) >= 'a' && LOWER(c) <= 'z')\n#define IS_NUM(c)           ((c) >= '0' && (c) <= '9')\n#define IS_ALPHANUM(c)      (IS_ALPHA(c) || IS_NUM(c))\n#define IS_HEX(c)           (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))\n#define IS_MARK(c)          ((c) == '-' || (c) == '_' || (c) == '.' || \\\n  (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\\'' || (c) == '(' || \\\n  (c) == ')')\n#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \\\n  (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \\\n  (c) == '$' || (c) == ',')\n\n#define STRICT_TOKEN(c)     (tokens[(unsigned char)c])\n\n#if HTTP_PARSER_STRICT\n#define TOKEN(c)            (tokens[(unsigned char)c])\n#define IS_URL_CHAR(c)      (BIT_AT(normal_url_char, (unsigned char)c))\n#define IS_HOST_CHAR(c)     (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')\n#else\n#define TOKEN(c)            ((c == ' ') ? ' ' : tokens[(unsigned char)c])\n#define IS_URL_CHAR(c)                                                         \\\n  (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))\n#define IS_HOST_CHAR(c)                                                        \\\n  (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')\n#endif\n\n\n#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)\n\n\n#if HTTP_PARSER_STRICT\n# define STRICT_CHECK(cond)                                          \\\ndo {                                                                 \\\n  if (cond) {                                                        \\\n    SET_ERRNO(HPE_STRICT);                                           \\\n    goto error;                                                      \\\n  }                                                                  \\\n} while (0)\n# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)\n#else\n# define STRICT_CHECK(cond)\n# define NEW_MESSAGE() start_state\n#endif\n\n\n/* Map errno values to strings for human-readable output */\n#define HTTP_STRERROR_GEN(n, s) { \"HPE_\" #n, s },\nstatic struct {\n  const char *name;\n  const char *description;\n} http_strerror_tab[] = {\n  HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)\n};\n#undef HTTP_STRERROR_GEN\n\nint http_message_needs_eof(const http_parser *parser);\n\n/* Our URL parser.\n *\n * This is designed to be shared by http_parser_execute() for URL validation,\n * hence it has a state transition + byte-for-byte interface. In addition, it\n * is meant to be embedded in http_parser_parse_url(), which does the dirty\n * work of turning state transitions URL components for its API.\n *\n * This function should only be invoked with non-space characters. It is\n * assumed that the caller cares about (and can detect) the transition between\n * URL and non-URL states by looking for these.\n */\nstatic enum state ICACHE_FLASH_ATTR parse_url_char(enum state s, const char ch)\n{\n  if (ch == ' ' || ch == '\\r' || ch == '\\n') {\n    return s_dead;\n  }\n\n#if HTTP_PARSER_STRICT\n  if (ch == '\\t' || ch == '\\f') {\n    return s_dead;\n  }\n#endif\n\n  switch (s) {\n    case s_req_spaces_before_url:\n      /* Proxied requests are followed by scheme of an absolute URI (alpha).\n       * All methods except CONNECT are followed by '/' or '*'.\n       */\n\n      if (ch == '/' || ch == '*') {\n        return s_req_path;\n      }\n\n      if (IS_ALPHA(ch)) {\n        return s_req_schema;\n      }\n\n      break;\n\n    case s_req_schema:\n      if (IS_ALPHA(ch)) {\n        return s;\n      }\n\n      if (ch == ':') {\n        return s_req_schema_slash;\n      }\n\n      break;\n\n    case s_req_schema_slash:\n      if (ch == '/') {\n        return s_req_schema_slash_slash;\n      }\n\n      break;\n\n    case s_req_schema_slash_slash:\n      if (ch == '/') {\n        return s_req_server_start;\n      }\n\n      break;\n\n    case s_req_server_with_at:\n      if (ch == '@') {\n        return s_dead;\n      }\n\n    /* FALLTHROUGH */\n    case s_req_server_start:\n    case s_req_server:\n      if (ch == '/') {\n        return s_req_path;\n      }\n\n      if (ch == '?') {\n        return s_req_query_string_start;\n      }\n\n      if (ch == '@') {\n        return s_req_server_with_at;\n      }\n\n      if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {\n        return s_req_server;\n      }\n\n      break;\n\n    case s_req_path:\n      if (IS_URL_CHAR(ch)) {\n        return s;\n      }\n\n      switch (ch) {\n        case '?':\n          return s_req_query_string_start;\n\n        case '#':\n          return s_req_fragment_start;\n      }\n\n      break;\n\n    case s_req_query_string_start:\n    case s_req_query_string:\n      if (IS_URL_CHAR(ch)) {\n        return s_req_query_string;\n      }\n\n      switch (ch) {\n        case '?':\n          /* allow extra '?' in query string */\n          return s_req_query_string;\n\n        case '#':\n          return s_req_fragment_start;\n      }\n\n      break;\n\n    case s_req_fragment_start:\n      if (IS_URL_CHAR(ch)) {\n        return s_req_fragment;\n      }\n\n      switch (ch) {\n        case '?':\n          return s_req_fragment;\n\n        case '#':\n          return s;\n      }\n\n      break;\n\n    case s_req_fragment:\n      if (IS_URL_CHAR(ch)) {\n        return s;\n      }\n\n      switch (ch) {\n        case '?':\n        case '#':\n          return s;\n      }\n\n      break;\n\n    default:\n      break;\n  }\n\n  /* We should never fall out of the switch above unless there's an error */\n  return s_dead;\n}\n\nsize_t ICACHE_FLASH_ATTR http_parser_execute (http_parser *parser,\n                            const http_parser_settings *settings,\n                            const char *data,\n                            size_t len)\n{\n  char c, ch;\n  int8_t unhex_val;\n  const char *p = data;\n  const char *header_field_mark = 0;\n  const char *header_value_mark = 0;\n  const char *url_mark = 0;\n  const char *body_mark = 0;\n  const char *status_mark = 0;\n  enum state p_state = (enum state) parser->state;\n\n  /* We're in an error state. Don't bother doing anything. */\n  if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {\n    return 0;\n  }\n\n  if (len == 0) {\n    switch (CURRENT_STATE()) {\n      case s_body_identity_eof:\n        /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if\n         * we got paused.\n         */\n        CALLBACK_NOTIFY_NOADVANCE(message_complete);\n        return 0;\n\n      case s_dead:\n      case s_start_req_or_res:\n      case s_start_res:\n      case s_start_req:\n        return 0;\n\n      default:\n        SET_ERRNO(HPE_INVALID_EOF_STATE);\n        return 1;\n    }\n  }\n\n\n  if (CURRENT_STATE() == s_header_field)\n    header_field_mark = data;\n  if (CURRENT_STATE() == s_header_value)\n    header_value_mark = data;\n  switch (CURRENT_STATE()) {\n  case s_req_path:\n  case s_req_schema:\n  case s_req_schema_slash:\n  case s_req_schema_slash_slash:\n  case s_req_server_start:\n  case s_req_server:\n  case s_req_server_with_at:\n  case s_req_query_string_start:\n  case s_req_query_string:\n  case s_req_fragment_start:\n  case s_req_fragment:\n    url_mark = data;\n    break;\n  case s_res_status:\n    status_mark = data;\n    break;\n  default:\n    break;\n  }\n\n  for (p=data; p != data + len; p++) {\n    ch = *p;\n\n    if (PARSING_HEADER(CURRENT_STATE()))\n      COUNT_HEADER_SIZE(1);\n\nreexecute:\n    switch (CURRENT_STATE()) {\n\n      case s_dead:\n        /* this state is used after a 'Connection: close' message\n         * the parser will error out if it reads another message\n         */\n        if (LIKELY(ch == CR || ch == LF))\n          break;\n\n        SET_ERRNO(HPE_CLOSED_CONNECTION);\n        goto error;\n\n      case s_start_req_or_res:\n      {\n        if (ch == CR || ch == LF)\n          break;\n        parser->flags = 0;\n        parser->content_length = ULLONG_MAX;\n\n        if (ch == 'H') {\n          UPDATE_STATE(s_res_or_resp_H);\n\n          CALLBACK_NOTIFY(message_begin);\n        } else {\n          parser->type = HTTP_REQUEST;\n          UPDATE_STATE(s_start_req);\n          REEXECUTE();\n        }\n\n        break;\n      }\n\n      case s_res_or_resp_H:\n        if (ch == 'T') {\n          parser->type = HTTP_RESPONSE;\n          UPDATE_STATE(s_res_HT);\n        } else {\n          if (UNLIKELY(ch != 'E')) {\n            SET_ERRNO(HPE_INVALID_CONSTANT);\n            goto error;\n          }\n\n          parser->type = HTTP_REQUEST;\n          parser->method = HTTP_HEAD;\n          parser->index = 2;\n          UPDATE_STATE(s_req_method);\n        }\n        break;\n\n      case s_start_res:\n      {\n        parser->flags = 0;\n        parser->content_length = ULLONG_MAX;\n\n        switch (ch) {\n          case 'H':\n            UPDATE_STATE(s_res_H);\n            break;\n\n          case CR:\n          case LF:\n            break;\n\n          default:\n            SET_ERRNO(HPE_INVALID_CONSTANT);\n            goto error;\n        }\n\n        CALLBACK_NOTIFY(message_begin);\n        break;\n      }\n\n      case s_res_H:\n        STRICT_CHECK(ch != 'T');\n        UPDATE_STATE(s_res_HT);\n        break;\n\n      case s_res_HT:\n        STRICT_CHECK(ch != 'T');\n        UPDATE_STATE(s_res_HTT);\n        break;\n\n      case s_res_HTT:\n        STRICT_CHECK(ch != 'P');\n        UPDATE_STATE(s_res_HTTP);\n        break;\n\n      case s_res_HTTP:\n        STRICT_CHECK(ch != '/');\n        UPDATE_STATE(s_res_first_http_major);\n        break;\n\n      case s_res_first_http_major:\n        if (UNLIKELY(ch < '0' || ch > '9')) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        parser->http_major = ch - '0';\n        UPDATE_STATE(s_res_http_major);\n        break;\n\n      /* major HTTP version or dot */\n      case s_res_http_major:\n      {\n        if (ch == '.') {\n          UPDATE_STATE(s_res_first_http_minor);\n          break;\n        }\n\n        if (!IS_NUM(ch)) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        parser->http_major *= 10;\n        parser->http_major += ch - '0';\n\n        if (UNLIKELY(parser->http_major > 999)) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        break;\n      }\n\n      /* first digit of minor HTTP version */\n      case s_res_first_http_minor:\n        if (UNLIKELY(!IS_NUM(ch))) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        parser->http_minor = ch - '0';\n        UPDATE_STATE(s_res_http_minor);\n        break;\n\n      /* minor HTTP version or end of request line */\n      case s_res_http_minor:\n      {\n        if (ch == ' ') {\n          UPDATE_STATE(s_res_first_status_code);\n          break;\n        }\n\n        if (UNLIKELY(!IS_NUM(ch))) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        parser->http_minor *= 10;\n        parser->http_minor += ch - '0';\n\n        if (UNLIKELY(parser->http_minor > 999)) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        break;\n      }\n\n      case s_res_first_status_code:\n      {\n        if (!IS_NUM(ch)) {\n          if (ch == ' ') {\n            break;\n          }\n\n          SET_ERRNO(HPE_INVALID_STATUS);\n          goto error;\n        }\n        parser->status_code = ch - '0';\n        UPDATE_STATE(s_res_status_code);\n        break;\n      }\n\n      case s_res_status_code:\n      {\n        if (!IS_NUM(ch)) {\n          switch (ch) {\n            case ' ':\n              UPDATE_STATE(s_res_status_start);\n              break;\n            case CR:\n              UPDATE_STATE(s_res_line_almost_done);\n              break;\n            case LF:\n              UPDATE_STATE(s_header_field_start);\n              break;\n            default:\n              SET_ERRNO(HPE_INVALID_STATUS);\n              goto error;\n          }\n          break;\n        }\n\n        parser->status_code *= 10;\n        parser->status_code += ch - '0';\n\n        if (UNLIKELY(parser->status_code > 999)) {\n          SET_ERRNO(HPE_INVALID_STATUS);\n          goto error;\n        }\n\n        break;\n      }\n\n      case s_res_status_start:\n      {\n        if (ch == CR) {\n          UPDATE_STATE(s_res_line_almost_done);\n          break;\n        }\n\n        if (ch == LF) {\n          UPDATE_STATE(s_header_field_start);\n          break;\n        }\n\n        MARK(status);\n        UPDATE_STATE(s_res_status);\n        parser->index = 0;\n        break;\n      }\n\n      case s_res_status:\n        if (ch == CR) {\n          UPDATE_STATE(s_res_line_almost_done);\n          CALLBACK_DATA(status);\n          break;\n        }\n\n        if (ch == LF) {\n          UPDATE_STATE(s_header_field_start);\n          CALLBACK_DATA(status);\n          break;\n        }\n\n        break;\n\n      case s_res_line_almost_done:\n        STRICT_CHECK(ch != LF);\n        UPDATE_STATE(s_header_field_start);\n        break;\n\n      case s_start_req:\n      {\n        if (ch == CR || ch == LF)\n          break;\n        parser->flags = 0;\n        parser->content_length = ULLONG_MAX;\n\n        if (UNLIKELY(!IS_ALPHA(ch))) {\n          SET_ERRNO(HPE_INVALID_METHOD);\n          goto error;\n        }\n\n        parser->method = (enum http_method) 0;\n        parser->index = 1;\n        switch (ch) {\n          case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;\n          case 'D': parser->method = HTTP_DELETE; break;\n          case 'G': parser->method = HTTP_GET; break;\n          case 'H': parser->method = HTTP_HEAD; break;\n          case 'L': parser->method = HTTP_LOCK; break;\n          case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break;\n          case 'N': parser->method = HTTP_NOTIFY; break;\n          case 'O': parser->method = HTTP_OPTIONS; break;\n          case 'P': parser->method = HTTP_POST;\n            /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */\n            break;\n          case 'R': parser->method = HTTP_REPORT; break;\n          case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;\n          case 'T': parser->method = HTTP_TRACE; break;\n          case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;\n          default:\n            SET_ERRNO(HPE_INVALID_METHOD);\n            goto error;\n        }\n        UPDATE_STATE(s_req_method);\n\n        CALLBACK_NOTIFY(message_begin);\n\n        break;\n      }\n\n      case s_req_method:\n      {\n        const char *matcher;\n        if (UNLIKELY(ch == '\\0')) {\n          SET_ERRNO(HPE_INVALID_METHOD);\n          goto error;\n        }\n\n        matcher = method_strings[parser->method];\n        if (ch == ' ' && matcher[parser->index] == '\\0') {\n          UPDATE_STATE(s_req_spaces_before_url);\n        } else if (ch == matcher[parser->index]) {\n          ; /* nada */\n        } else if (parser->method == HTTP_CONNECT) {\n          if (parser->index == 1 && ch == 'H') {\n            parser->method = HTTP_CHECKOUT;\n          } else if (parser->index == 2  && ch == 'P') {\n            parser->method = HTTP_COPY;\n          } else {\n            SET_ERRNO(HPE_INVALID_METHOD);\n            goto error;\n          }\n        } else if (parser->method == HTTP_MKCOL) {\n          if (parser->index == 1 && ch == 'O') {\n            parser->method = HTTP_MOVE;\n          } else if (parser->index == 1 && ch == 'E') {\n            parser->method = HTTP_MERGE;\n          } else if (parser->index == 1 && ch == '-') {\n            parser->method = HTTP_MSEARCH;\n          } else if (parser->index == 2 && ch == 'A') {\n            parser->method = HTTP_MKACTIVITY;\n          } else if (parser->index == 3 && ch == 'A') {\n            parser->method = HTTP_MKCALENDAR;\n          } else {\n            SET_ERRNO(HPE_INVALID_METHOD);\n            goto error;\n          }\n        } else if (parser->method == HTTP_SUBSCRIBE) {\n          if (parser->index == 1 && ch == 'E') {\n            parser->method = HTTP_SEARCH;\n          } else {\n            SET_ERRNO(HPE_INVALID_METHOD);\n            goto error;\n          }\n        } else if (parser->index == 1 && parser->method == HTTP_POST) {\n          if (ch == 'R') {\n            parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */\n          } else if (ch == 'U') {\n            parser->method = HTTP_PUT; /* or HTTP_PURGE */\n          } else if (ch == 'A') {\n            parser->method = HTTP_PATCH;\n          } else {\n            SET_ERRNO(HPE_INVALID_METHOD);\n            goto error;\n          }\n        } else if (parser->index == 2) {\n          if (parser->method == HTTP_PUT) {\n            if (ch == 'R') {\n              parser->method = HTTP_PURGE;\n            } else {\n              SET_ERRNO(HPE_INVALID_METHOD);\n              goto error;\n            }\n          } else if (parser->method == HTTP_UNLOCK) {\n            if (ch == 'S') {\n              parser->method = HTTP_UNSUBSCRIBE;\n            } else {\n              SET_ERRNO(HPE_INVALID_METHOD);\n              goto error;\n            }\n          } else {\n            SET_ERRNO(HPE_INVALID_METHOD);\n            goto error;\n          }\n        } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {\n          parser->method = HTTP_PROPPATCH;\n        } else {\n          SET_ERRNO(HPE_INVALID_METHOD);\n          goto error;\n        }\n\n        ++parser->index;\n        break;\n      }\n\n      case s_req_spaces_before_url:\n      {\n        if (ch == ' ') break;\n\n        MARK(url);\n        if (parser->method == HTTP_CONNECT) {\n          UPDATE_STATE(s_req_server_start);\n        }\n\n        UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));\n        if (UNLIKELY(CURRENT_STATE() == s_dead)) {\n          SET_ERRNO(HPE_INVALID_URL);\n          goto error;\n        }\n\n        break;\n      }\n\n      case s_req_schema:\n      case s_req_schema_slash:\n      case s_req_schema_slash_slash:\n      case s_req_server_start:\n      {\n        switch (ch) {\n          /* No whitespace allowed here */\n          case ' ':\n          case CR:\n          case LF:\n            SET_ERRNO(HPE_INVALID_URL);\n            goto error;\n          default:\n            UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));\n            if (UNLIKELY(CURRENT_STATE() == s_dead)) {\n              SET_ERRNO(HPE_INVALID_URL);\n              goto error;\n            }\n        }\n\n        break;\n      }\n\n      case s_req_server:\n      case s_req_server_with_at:\n      case s_req_path:\n      case s_req_query_string_start:\n      case s_req_query_string:\n      case s_req_fragment_start:\n      case s_req_fragment:\n      {\n        switch (ch) {\n          case ' ':\n            UPDATE_STATE(s_req_http_start);\n            CALLBACK_DATA(url);\n            break;\n          case CR:\n          case LF:\n            parser->http_major = 0;\n            parser->http_minor = 9;\n            UPDATE_STATE((ch == CR) ?\n              s_req_line_almost_done :\n              s_header_field_start);\n            CALLBACK_DATA(url);\n            break;\n          default:\n            UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));\n            if (UNLIKELY(CURRENT_STATE() == s_dead)) {\n              SET_ERRNO(HPE_INVALID_URL);\n              goto error;\n            }\n        }\n        break;\n      }\n\n      case s_req_http_start:\n        switch (ch) {\n          case 'H':\n            UPDATE_STATE(s_req_http_H);\n            break;\n          case ' ':\n            break;\n          default:\n            SET_ERRNO(HPE_INVALID_CONSTANT);\n            goto error;\n        }\n        break;\n\n      case s_req_http_H:\n        STRICT_CHECK(ch != 'T');\n        UPDATE_STATE(s_req_http_HT);\n        break;\n\n      case s_req_http_HT:\n        STRICT_CHECK(ch != 'T');\n        UPDATE_STATE(s_req_http_HTT);\n        break;\n\n      case s_req_http_HTT:\n        STRICT_CHECK(ch != 'P');\n        UPDATE_STATE(s_req_http_HTTP);\n        break;\n\n      case s_req_http_HTTP:\n        STRICT_CHECK(ch != '/');\n        UPDATE_STATE(s_req_first_http_major);\n        break;\n\n      /* first digit of major HTTP version */\n      case s_req_first_http_major:\n        if (UNLIKELY(ch < '1' || ch > '9')) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        parser->http_major = ch - '0';\n        UPDATE_STATE(s_req_http_major);\n        break;\n\n      /* major HTTP version or dot */\n      case s_req_http_major:\n      {\n        if (ch == '.') {\n          UPDATE_STATE(s_req_first_http_minor);\n          break;\n        }\n\n        if (UNLIKELY(!IS_NUM(ch))) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        parser->http_major *= 10;\n        parser->http_major += ch - '0';\n\n        if (UNLIKELY(parser->http_major > 999)) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        break;\n      }\n\n      /* first digit of minor HTTP version */\n      case s_req_first_http_minor:\n        if (UNLIKELY(!IS_NUM(ch))) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        parser->http_minor = ch - '0';\n        UPDATE_STATE(s_req_http_minor);\n        break;\n\n      /* minor HTTP version or end of request line */\n      case s_req_http_minor:\n      {\n        if (ch == CR) {\n          UPDATE_STATE(s_req_line_almost_done);\n          break;\n        }\n\n        if (ch == LF) {\n          UPDATE_STATE(s_header_field_start);\n          break;\n        }\n\n        /* XXX allow spaces after digit? */\n\n        if (UNLIKELY(!IS_NUM(ch))) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        parser->http_minor *= 10;\n        parser->http_minor += ch - '0';\n\n        if (UNLIKELY(parser->http_minor > 999)) {\n          SET_ERRNO(HPE_INVALID_VERSION);\n          goto error;\n        }\n\n        break;\n      }\n\n      /* end of request line */\n      case s_req_line_almost_done:\n      {\n        if (UNLIKELY(ch != LF)) {\n          SET_ERRNO(HPE_LF_EXPECTED);\n          goto error;\n        }\n\n        UPDATE_STATE(s_header_field_start);\n        break;\n      }\n\n      case s_header_field_start:\n      {\n        if (ch == CR) {\n          UPDATE_STATE(s_headers_almost_done);\n          break;\n        }\n\n        if (ch == LF) {\n          /* they might be just sending \\n instead of \\r\\n so this would be\n           * the second \\n to denote the end of headers*/\n          UPDATE_STATE(s_headers_almost_done);\n          REEXECUTE();\n        }\n\n        c = TOKEN(ch);\n\n        if (UNLIKELY(!c)) {\n          SET_ERRNO(HPE_INVALID_HEADER_TOKEN);\n          goto error;\n        }\n\n        MARK(header_field);\n\n        parser->index = 0;\n        UPDATE_STATE(s_header_field);\n\n        switch (c) {\n          case 'c':\n            parser->header_state = h_C;\n            break;\n\n          case 'p':\n            parser->header_state = h_matching_proxy_connection;\n            break;\n\n          case 't':\n            parser->header_state = h_matching_transfer_encoding;\n            break;\n\n          case 'u':\n            parser->header_state = h_matching_upgrade;\n            break;\n\n          default:\n            parser->header_state = h_general;\n            break;\n        }\n        break;\n      }\n\n      case s_header_field:\n      {\n        const char* start = p;\n        for (; p != data + len; p++) {\n          ch = *p;\n          c = TOKEN(ch);\n\n          if (!c)\n            break;\n\n          switch (parser->header_state) {\n            case h_general:\n              break;\n\n            case h_C:\n              parser->index++;\n              parser->header_state = (c == 'o' ? h_CO : h_general);\n              break;\n\n            case h_CO:\n              parser->index++;\n              parser->header_state = (c == 'n' ? h_CON : h_general);\n              break;\n\n            case h_CON:\n              parser->index++;\n              switch (c) {\n                case 'n':\n                  parser->header_state = h_matching_connection;\n                  break;\n                case 't':\n                  parser->header_state = h_matching_content_length;\n                  break;\n                default:\n                  parser->header_state = h_general;\n                  break;\n              }\n              break;\n\n            /* connection */\n\n            case h_matching_connection:\n              parser->index++;\n              if (parser->index > sizeof(CONNECTION)-1\n                  || c != CONNECTION[parser->index]) {\n                parser->header_state = h_general;\n              } else if (parser->index == sizeof(CONNECTION)-2) {\n                parser->header_state = h_connection;\n              }\n              break;\n\n            /* proxy-connection */\n\n            case h_matching_proxy_connection:\n              parser->index++;\n              if (parser->index > sizeof(PROXY_CONNECTION)-1\n                  || c != PROXY_CONNECTION[parser->index]) {\n                parser->header_state = h_general;\n              } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {\n                parser->header_state = h_connection;\n              }\n              break;\n\n            /* content-length */\n\n            case h_matching_content_length:\n              parser->index++;\n              if (parser->index > sizeof(CONTENT_LENGTH)-1\n                  || c != CONTENT_LENGTH[parser->index]) {\n                parser->header_state = h_general;\n              } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {\n                parser->header_state = h_content_length;\n              }\n              break;\n\n            /* transfer-encoding */\n\n            case h_matching_transfer_encoding:\n              parser->index++;\n              if (parser->index > sizeof(TRANSFER_ENCODING)-1\n                  || c != TRANSFER_ENCODING[parser->index]) {\n                parser->header_state = h_general;\n              } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {\n                parser->header_state = h_transfer_encoding;\n              }\n              break;\n\n            /* upgrade */\n\n            case h_matching_upgrade:\n              parser->index++;\n              if (parser->index > sizeof(UPGRADE)-1\n                  || c != UPGRADE[parser->index]) {\n                parser->header_state = h_general;\n              } else if (parser->index == sizeof(UPGRADE)-2) {\n                parser->header_state = h_upgrade;\n              }\n              break;\n\n            case h_connection:\n            case h_content_length:\n            case h_transfer_encoding:\n            case h_upgrade:\n              if (ch != ' ') parser->header_state = h_general;\n              break;\n\n            default:\n              assert(0 && \"Unknown header_state\");\n              break;\n          }\n        }\n\n        COUNT_HEADER_SIZE(p - start);\n\n        if (p == data + len) {\n          --p;\n          break;\n        }\n\n        if (ch == ':') {\n          UPDATE_STATE(s_header_value_discard_ws);\n          CALLBACK_DATA(header_field);\n          break;\n        }\n\n        SET_ERRNO(HPE_INVALID_HEADER_TOKEN);\n        goto error;\n      }\n\n      case s_header_value_discard_ws:\n        if (ch == ' ' || ch == '\\t') break;\n\n        if (ch == CR) {\n          UPDATE_STATE(s_header_value_discard_ws_almost_done);\n          break;\n        }\n\n        if (ch == LF) {\n          UPDATE_STATE(s_header_value_discard_lws);\n          break;\n        }\n\n        /* FALLTHROUGH */\n\n      case s_header_value_start:\n      {\n        MARK(header_value);\n\n        UPDATE_STATE(s_header_value);\n        parser->index = 0;\n\n        c = LOWER(ch);\n\n        switch (parser->header_state) {\n          case h_upgrade:\n            parser->flags |= F_UPGRADE;\n            parser->header_state = h_general;\n            break;\n\n          case h_transfer_encoding:\n            /* looking for 'Transfer-Encoding: chunked' */\n            if ('c' == c) {\n              parser->header_state = h_matching_transfer_encoding_chunked;\n            } else {\n              parser->header_state = h_general;\n            }\n            break;\n\n          case h_content_length:\n            if (UNLIKELY(!IS_NUM(ch))) {\n              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);\n              goto error;\n            }\n\n            parser->content_length = ch - '0';\n            break;\n\n          case h_connection:\n            /* looking for 'Connection: keep-alive' */\n            if (c == 'k') {\n              parser->header_state = h_matching_connection_keep_alive;\n            /* looking for 'Connection: close' */\n            } else if (c == 'c') {\n              parser->header_state = h_matching_connection_close;\n            } else if (c == 'u') {\n              parser->header_state = h_matching_connection_upgrade;\n            } else {\n              parser->header_state = h_matching_connection_token;\n            }\n            break;\n\n          /* Multi-value `Connection` header */\n          case h_matching_connection_token_start:\n            break;\n\n          default:\n            parser->header_state = h_general;\n            break;\n        }\n        break;\n      }\n\n      case s_header_value:\n      {\n        const char* start = p;\n        enum header_states h_state = (enum header_states) parser->header_state;\n        for (; p != data + len; p++) {\n          ch = *p;\n          if (ch == CR) {\n            UPDATE_STATE(s_header_almost_done);\n            parser->header_state = h_state;\n            CALLBACK_DATA(header_value);\n            break;\n          }\n\n          if (ch == LF) {\n            UPDATE_STATE(s_header_almost_done);\n            COUNT_HEADER_SIZE(p - start);\n            parser->header_state = h_state;\n            CALLBACK_DATA_NOADVANCE(header_value);\n            REEXECUTE();\n          }\n\n          c = LOWER(ch);\n\n          switch (h_state) {\n            case h_general:\n            {\n              const char* p_cr;\n              const char* p_lf;\n              size_t limit = data + len - p;\n\n              limit = MIN(limit, HTTP_MAX_HEADER_SIZE);\n\n              p_cr = (const char*) memchr(p, CR, limit);\n              p_lf = (const char*) memchr(p, LF, limit);\n              if (p_cr != NULL) {\n                if (p_lf != NULL && p_cr >= p_lf)\n                  p = p_lf;\n                else\n                  p = p_cr;\n              } else if (UNLIKELY(p_lf != NULL)) {\n                p = p_lf;\n              } else {\n                p = data + len;\n              }\n              --p;\n\n              break;\n            }\n\n            case h_connection:\n            case h_transfer_encoding:\n              assert(0 && \"Shouldn't get here.\");\n              break;\n\n            case h_content_length:\n            {\n              uint64_t t;\n\n              if (ch == ' ') break;\n\n              if (UNLIKELY(!IS_NUM(ch))) {\n                SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);\n                parser->header_state = h_state;\n                goto error;\n              }\n\n              t = parser->content_length;\n              t *= 10;\n              t += ch - '0';\n\n              /* Overflow? Test against a conservative limit for simplicity. */\n              if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) {\n                SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);\n                parser->header_state = h_state;\n                goto error;\n              }\n\n              parser->content_length = t;\n              break;\n            }\n\n            /* Transfer-Encoding: chunked */\n            case h_matching_transfer_encoding_chunked:\n              parser->index++;\n              if (parser->index > sizeof(CHUNKED)-1\n                  || c != CHUNKED[parser->index]) {\n                h_state = h_general;\n              } else if (parser->index == sizeof(CHUNKED)-2) {\n                h_state = h_transfer_encoding_chunked;\n              }\n              break;\n\n            case h_matching_connection_token_start:\n              /* looking for 'Connection: keep-alive' */\n              if (c == 'k') {\n                h_state = h_matching_connection_keep_alive;\n              /* looking for 'Connection: close' */\n              } else if (c == 'c') {\n                h_state = h_matching_connection_close;\n              } else if (c == 'u') {\n                h_state = h_matching_connection_upgrade;\n              } else if (STRICT_TOKEN(c)) {\n                h_state = h_matching_connection_token;\n              } else if (c == ' ' || c == '\\t') {\n                /* Skip lws */\n              } else {\n                h_state = h_general;\n              }\n              break;\n\n            /* looking for 'Connection: keep-alive' */\n            case h_matching_connection_keep_alive:\n              parser->index++;\n              if (parser->index > sizeof(KEEP_ALIVE)-1\n                  || c != KEEP_ALIVE[parser->index]) {\n                h_state = h_matching_connection_token;\n              } else if (parser->index == sizeof(KEEP_ALIVE)-2) {\n                h_state = h_connection_keep_alive;\n              }\n              break;\n\n            /* looking for 'Connection: close' */\n            case h_matching_connection_close:\n              parser->index++;\n              if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {\n                h_state = h_matching_connection_token;\n              } else if (parser->index == sizeof(CLOSE)-2) {\n                h_state = h_connection_close;\n              }\n              break;\n\n            /* looking for 'Connection: upgrade' */\n            case h_matching_connection_upgrade:\n              parser->index++;\n              if (parser->index > sizeof(UPGRADE) - 1 ||\n                  c != UPGRADE[parser->index]) {\n                h_state = h_matching_connection_token;\n              } else if (parser->index == sizeof(UPGRADE)-2) {\n                h_state = h_connection_upgrade;\n              }\n              break;\n\n            case h_matching_connection_token:\n              if (ch == ',') {\n                h_state = h_matching_connection_token_start;\n                parser->index = 0;\n              }\n              break;\n\n            case h_transfer_encoding_chunked:\n              if (ch != ' ') h_state = h_general;\n              break;\n\n            case h_connection_keep_alive:\n            case h_connection_close:\n            case h_connection_upgrade:\n              if (ch == ',') {\n                if (h_state == h_connection_keep_alive) {\n                  parser->flags |= F_CONNECTION_KEEP_ALIVE;\n                } else if (h_state == h_connection_close) {\n                  parser->flags |= F_CONNECTION_CLOSE;\n                } else if (h_state == h_connection_upgrade) {\n                  parser->flags |= F_CONNECTION_UPGRADE;\n                }\n                h_state = h_matching_connection_token_start;\n                parser->index = 0;\n              } else if (ch != ' ') {\n                h_state = h_matching_connection_token;\n              }\n              break;\n\n            default:\n              UPDATE_STATE(s_header_value);\n              h_state = h_general;\n              break;\n          }\n        }\n        parser->header_state = h_state;\n\n        COUNT_HEADER_SIZE(p - start);\n\n        if (p == data + len)\n          --p;\n        break;\n      }\n\n      case s_header_almost_done:\n      {\n        STRICT_CHECK(ch != LF);\n\n        UPDATE_STATE(s_header_value_lws);\n        break;\n      }\n\n      case s_header_value_lws:\n      {\n        if (ch == ' ' || ch == '\\t') {\n          UPDATE_STATE(s_header_value_start);\n          REEXECUTE();\n        }\n\n        /* finished the header */\n        switch (parser->header_state) {\n          case h_connection_keep_alive:\n            parser->flags |= F_CONNECTION_KEEP_ALIVE;\n            break;\n          case h_connection_close:\n            parser->flags |= F_CONNECTION_CLOSE;\n            break;\n          case h_transfer_encoding_chunked:\n            parser->flags |= F_CHUNKED;\n            break;\n          case h_connection_upgrade:\n            parser->flags |= F_CONNECTION_UPGRADE;\n            break;\n          default:\n            break;\n        }\n\n        UPDATE_STATE(s_header_field_start);\n        REEXECUTE();\n      }\n\n      case s_header_value_discard_ws_almost_done:\n      {\n        STRICT_CHECK(ch != LF);\n        UPDATE_STATE(s_header_value_discard_lws);\n        break;\n      }\n\n      case s_header_value_discard_lws:\n      {\n        if (ch == ' ' || ch == '\\t') {\n          UPDATE_STATE(s_header_value_discard_ws);\n          break;\n        } else {\n          switch (parser->header_state) {\n            case h_connection_keep_alive:\n              parser->flags |= F_CONNECTION_KEEP_ALIVE;\n              break;\n            case h_connection_close:\n              parser->flags |= F_CONNECTION_CLOSE;\n              break;\n            case h_connection_upgrade:\n              parser->flags |= F_CONNECTION_UPGRADE;\n              break;\n            case h_transfer_encoding_chunked:\n              parser->flags |= F_CHUNKED;\n              break;\n            default:\n              break;\n          }\n\n          /* header value was empty */\n          MARK(header_value);\n          UPDATE_STATE(s_header_field_start);\n          CALLBACK_DATA_NOADVANCE(header_value);\n          REEXECUTE();\n        }\n      }\n\n      case s_headers_almost_done:\n      {\n        STRICT_CHECK(ch != LF);\n\n        if (parser->flags & F_TRAILING) {\n          /* End of a chunked request */\n          UPDATE_STATE(NEW_MESSAGE());\n          CALLBACK_NOTIFY(message_complete);\n          break;\n        }\n\n        UPDATE_STATE(s_headers_done);\n\n        /* Set this here so that on_headers_complete() callbacks can see it */\n        parser->upgrade =\n          ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) ==\n           (F_UPGRADE | F_CONNECTION_UPGRADE) ||\n           parser->method == HTTP_CONNECT);\n\n        /* Here we call the headers_complete callback. This is somewhat\n         * different than other callbacks because if the user returns 1, we\n         * will interpret that as saying that this message has no body. This\n         * is needed for the annoying case of recieving a response to a HEAD\n         * request.\n         *\n         * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so\n         * we have to simulate it by handling a change in errno below.\n         */\n        if (settings->on_headers_complete) {\n          switch (settings->on_headers_complete(parser)) {\n            case 0:\n              break;\n\n            case 1:\n              parser->flags |= F_SKIPBODY;\n              break;\n\n            default:\n              SET_ERRNO(HPE_CB_headers_complete);\n              RETURN(p - data); /* Error */\n          }\n        }\n\n        if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {\n          RETURN(p - data);\n        }\n\n        REEXECUTE();\n      }\n\n      case s_headers_done:\n      {\n        STRICT_CHECK(ch != LF);\n\n        parser->nread = 0;\n\n        /* Exit, the rest of the connect is in a different protocol. */\n        if (parser->upgrade) {\n          UPDATE_STATE(NEW_MESSAGE());\n          CALLBACK_NOTIFY(message_complete);\n          RETURN((p - data) + 1);\n        }\n\n        if (parser->flags & F_SKIPBODY) {\n          UPDATE_STATE(NEW_MESSAGE());\n          CALLBACK_NOTIFY(message_complete);\n        } else if (parser->flags & F_CHUNKED) {\n          /* chunked encoding - ignore Content-Length header */\n          UPDATE_STATE(s_chunk_size_start);\n        } else {\n          if (parser->content_length == 0) {\n            /* Content-Length header given but zero: Content-Length: 0\\r\\n */\n            UPDATE_STATE(NEW_MESSAGE());\n            CALLBACK_NOTIFY(message_complete);\n          } else if (parser->content_length != ULLONG_MAX) {\n            /* Content-Length header given and non-zero */\n            UPDATE_STATE(s_body_identity);\n          } else {\n            if (parser->type == HTTP_REQUEST ||\n                !http_message_needs_eof(parser)) {\n              /* Assume content-length 0 - read the next */\n              UPDATE_STATE(NEW_MESSAGE());\n              CALLBACK_NOTIFY(message_complete);\n            } else {\n              /* Read body until EOF */\n              UPDATE_STATE(s_body_identity_eof);\n            }\n          }\n        }\n\n        break;\n      }\n\n      case s_body_identity:\n      {\n        uint64_t to_read = MIN(parser->content_length,\n                               (uint64_t) ((data + len) - p));\n\n        assert(parser->content_length != 0\n            && parser->content_length != ULLONG_MAX);\n\n        /* The difference between advancing content_length and p is because\n         * the latter will automaticaly advance on the next loop iteration.\n         * Further, if content_length ends up at 0, we want to see the last\n         * byte again for our message complete callback.\n         */\n        MARK(body);\n        parser->content_length -= to_read;\n        p += to_read - 1;\n\n        if (parser->content_length == 0) {\n          UPDATE_STATE(s_message_done);\n\n          /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.\n           *\n           * The alternative to doing this is to wait for the next byte to\n           * trigger the data callback, just as in every other case. The\n           * problem with this is that this makes it difficult for the test\n           * harness to distinguish between complete-on-EOF and\n           * complete-on-length. It's not clear that this distinction is\n           * important for applications, but let's keep it for now.\n           */\n          CALLBACK_DATA_(body, p - body_mark + 1, p - data);\n          REEXECUTE();\n        }\n\n        break;\n      }\n\n      /* read until EOF */\n      case s_body_identity_eof:\n        MARK(body);\n        p = data + len - 1;\n\n        break;\n\n      case s_message_done:\n        UPDATE_STATE(NEW_MESSAGE());\n        CALLBACK_NOTIFY(message_complete);\n        break;\n\n      case s_chunk_size_start:\n      {\n        assert(parser->nread == 1);\n        assert(parser->flags & F_CHUNKED);\n\n        unhex_val = unhex[(unsigned char)ch];\n        if (UNLIKELY(unhex_val == -1)) {\n          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);\n          goto error;\n        }\n\n        parser->content_length = unhex_val;\n        UPDATE_STATE(s_chunk_size);\n        break;\n      }\n\n      case s_chunk_size:\n      {\n        uint64_t t;\n\n        assert(parser->flags & F_CHUNKED);\n\n        if (ch == CR) {\n          UPDATE_STATE(s_chunk_size_almost_done);\n          break;\n        }\n\n        unhex_val = unhex[(unsigned char)ch];\n\n        if (unhex_val == -1) {\n          if (ch == ';' || ch == ' ') {\n            UPDATE_STATE(s_chunk_parameters);\n            break;\n          }\n\n          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);\n          goto error;\n        }\n\n        t = parser->content_length;\n        t *= 16;\n        t += unhex_val;\n\n        /* Overflow? Test against a conservative limit for simplicity. */\n        if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) {\n          SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);\n          goto error;\n        }\n\n        parser->content_length = t;\n        break;\n      }\n\n      case s_chunk_parameters:\n      {\n        assert(parser->flags & F_CHUNKED);\n        /* just ignore this shit. TODO check for overflow */\n        if (ch == CR) {\n          UPDATE_STATE(s_chunk_size_almost_done);\n          break;\n        }\n        break;\n      }\n\n      case s_chunk_size_almost_done:\n      {\n        assert(parser->flags & F_CHUNKED);\n        STRICT_CHECK(ch != LF);\n\n        parser->nread = 0;\n\n        if (parser->content_length == 0) {\n          parser->flags |= F_TRAILING;\n          UPDATE_STATE(s_header_field_start);\n        } else {\n          UPDATE_STATE(s_chunk_data);\n        }\n        break;\n      }\n\n      case s_chunk_data:\n      {\n        uint64_t to_read = MIN(parser->content_length,\n                               (uint64_t) ((data + len) - p));\n\n        assert(parser->flags & F_CHUNKED);\n        assert(parser->content_length != 0\n            && parser->content_length != ULLONG_MAX);\n\n        /* See the explanation in s_body_identity for why the content\n         * length and data pointers are managed this way.\n         */\n        MARK(body);\n        parser->content_length -= to_read;\n        p += to_read - 1;\n\n        if (parser->content_length == 0) {\n          UPDATE_STATE(s_chunk_data_almost_done);\n        }\n\n        break;\n      }\n\n      case s_chunk_data_almost_done:\n        assert(parser->flags & F_CHUNKED);\n        assert(parser->content_length == 0);\n        STRICT_CHECK(ch != CR);\n        UPDATE_STATE(s_chunk_data_done);\n        CALLBACK_DATA(body);\n        break;\n\n      case s_chunk_data_done:\n        assert(parser->flags & F_CHUNKED);\n        STRICT_CHECK(ch != LF);\n        parser->nread = 0;\n        UPDATE_STATE(s_chunk_size_start);\n        break;\n\n      default:\n        assert(0 && \"unhandled state\");\n        SET_ERRNO(HPE_INVALID_INTERNAL_STATE);\n        goto error;\n    }\n  }\n\n  /* Run callbacks for any marks that we have leftover after we ran our of\n   * bytes. There should be at most one of these set, so it's OK to invoke\n   * them in series (unset marks will not result in callbacks).\n   *\n   * We use the NOADVANCE() variety of callbacks here because 'p' has already\n   * overflowed 'data' and this allows us to correct for the off-by-one that\n   * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'\n   * value that's in-bounds).\n   */\n\n  assert(((header_field_mark ? 1 : 0) +\n          (header_value_mark ? 1 : 0) +\n          (url_mark ? 1 : 0)  +\n          (body_mark ? 1 : 0) +\n          (status_mark ? 1 : 0)) <= 1);\n\n  CALLBACK_DATA_NOADVANCE(header_field);\n  CALLBACK_DATA_NOADVANCE(header_value);\n  CALLBACK_DATA_NOADVANCE(url);\n  CALLBACK_DATA_NOADVANCE(body);\n  CALLBACK_DATA_NOADVANCE(status);\n\n  RETURN(len);\n\nerror:\n  if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {\n    SET_ERRNO(HPE_UNKNOWN);\n  }\n\n  RETURN(p - data);\n}\n\n\n/* Does the parser need to see an EOF to find the end of the message? */\nint ICACHE_FLASH_ATTR http_message_needs_eof (const http_parser *parser)\n{\n  if (parser->type == HTTP_REQUEST) {\n    return 0;\n  }\n\n  /* See RFC 2616 section 4.4 */\n  if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */\n      parser->status_code == 204 ||     /* No Content */\n      parser->status_code == 304 ||     /* Not Modified */\n      parser->flags & F_SKIPBODY) {     /* response to a HEAD request */\n    return 0;\n  }\n\n  if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {\n    return 0;\n  }\n\n  return 1;\n}\n\n\nint ICACHE_FLASH_ATTR http_should_keep_alive (const http_parser *parser)\n{\n  if (parser->http_major > 0 && parser->http_minor > 0) {\n    /* HTTP/1.1 */\n    if (parser->flags & F_CONNECTION_CLOSE) {\n      return 0;\n    }\n  } else {\n    /* HTTP/1.0 or earlier */\n    if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {\n      return 0;\n    }\n  }\n\n  return !http_message_needs_eof(parser);\n}\n\n\nconst char * ICACHE_FLASH_ATTR http_method_str (enum http_method m)\n{\n  return ELEM_AT(method_strings, m, \"<unknown>\");\n}\n\n\nvoid ICACHE_FLASH_ATTR http_parser_init (http_parser *parser, enum http_parser_type t)\n{\n  void *data = parser->data; /* preserve application data */\n  memset(parser, 0, sizeof(*parser));\n  parser->data = data;\n  parser->type = t;\n  parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));\n  parser->http_errno = HPE_OK;\n}\n\nvoid ICACHE_FLASH_ATTR http_parser_settings_init(http_parser_settings *settings)\n{\n  memset(settings, 0, sizeof(*settings));\n}\n\nconst char * ICACHE_FLASH_ATTR http_errno_name(enum http_errno err) {\n  assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));\n  return http_strerror_tab[err].name;\n}\n\nconst char * ICACHE_FLASH_ATTR http_errno_description(enum http_errno err) {\n  assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));\n  return http_strerror_tab[err].description;\n}\n\nstatic enum http_host_state ICACHE_FLASH_ATTR http_parse_host_char(enum http_host_state s, const char ch) {\n  switch(s) {\n    case s_http_userinfo:\n    case s_http_userinfo_start:\n      if (ch == '@') {\n        return s_http_host_start;\n      }\n\n      if (IS_USERINFO_CHAR(ch)) {\n        return s_http_userinfo;\n      }\n      break;\n\n    case s_http_host_start:\n      if (ch == '[') {\n        return s_http_host_v6_start;\n      }\n\n      if (IS_HOST_CHAR(ch)) {\n        return s_http_host;\n      }\n\n      break;\n\n    case s_http_host:\n      if (IS_HOST_CHAR(ch)) {\n        return s_http_host;\n      }\n\n    /* FALLTHROUGH */\n    case s_http_host_v6_end:\n      if (ch == ':') {\n        return s_http_host_port_start;\n      }\n\n      break;\n\n    case s_http_host_v6:\n      if (ch == ']') {\n        return s_http_host_v6_end;\n      }\n\n    /* FALLTHROUGH */\n    case s_http_host_v6_start:\n      if (IS_HEX(ch) || ch == ':' || ch == '.') {\n        return s_http_host_v6;\n      }\n\n      break;\n\n    case s_http_host_port:\n    case s_http_host_port_start:\n      if (IS_NUM(ch)) {\n        return s_http_host_port;\n      }\n\n      break;\n\n    default:\n      break;\n  }\n  return s_http_host_dead;\n}\n\nstatic int ICACHE_FLASH_ATTR http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {\n  enum http_host_state s;\n\n  const char *p;\n  size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;\n\n  u->field_data[UF_HOST].len = 0;\n\n  s = found_at ? s_http_userinfo_start : s_http_host_start;\n\n  for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {\n    enum http_host_state new_s = http_parse_host_char(s, *p);\n\n    if (new_s == s_http_host_dead) {\n      return 1;\n    }\n\n    switch(new_s) {\n      case s_http_host:\n        if (s != s_http_host) {\n          u->field_data[UF_HOST].off = p - buf;\n        }\n        u->field_data[UF_HOST].len++;\n        break;\n\n      case s_http_host_v6:\n        if (s != s_http_host_v6) {\n          u->field_data[UF_HOST].off = p - buf;\n        }\n        u->field_data[UF_HOST].len++;\n        break;\n\n      case s_http_host_port:\n        if (s != s_http_host_port) {\n          u->field_data[UF_PORT].off = p - buf;\n          u->field_data[UF_PORT].len = 0;\n          u->field_set |= (1 << UF_PORT);\n        }\n        u->field_data[UF_PORT].len++;\n        break;\n\n      case s_http_userinfo:\n        if (s != s_http_userinfo) {\n          u->field_data[UF_USERINFO].off = p - buf ;\n          u->field_data[UF_USERINFO].len = 0;\n          u->field_set |= (1 << UF_USERINFO);\n        }\n        u->field_data[UF_USERINFO].len++;\n        break;\n\n      default:\n        break;\n    }\n    s = new_s;\n  }\n\n  /* Make sure we don't end somewhere unexpected */\n  switch (s) {\n    case s_http_host_start:\n    case s_http_host_v6_start:\n    case s_http_host_v6:\n    case s_http_host_port_start:\n    case s_http_userinfo:\n    case s_http_userinfo_start:\n      return 1;\n    default:\n      break;\n  }\n\n  return 0;\n}\n\nint ICACHE_FLASH_ATTR http_parser_parse_url(const char *buf, size_t buflen, int is_connect,\n                      struct http_parser_url *u)\n{\n  enum state s;\n  const char *p;\n  enum http_parser_url_fields uf, old_uf;\n  int found_at = 0;\n\n  u->port = u->field_set = 0;\n  s = is_connect ? s_req_server_start : s_req_spaces_before_url;\n  old_uf = UF_MAX;\n\n  for (p = buf; p < buf + buflen; p++) {\n    s = parse_url_char(s, *p);\n\n    /* Figure out the next field that we're operating on */\n    switch (s) {\n      case s_dead:\n        return 1;\n\n      /* Skip delimeters */\n      case s_req_schema_slash:\n      case s_req_schema_slash_slash:\n      case s_req_server_start:\n      case s_req_query_string_start:\n      case s_req_fragment_start:\n        continue;\n\n      case s_req_schema:\n        uf = UF_SCHEMA;\n        break;\n\n      case s_req_server_with_at:\n        found_at = 1;\n\n      /* FALLTROUGH */\n      case s_req_server:\n        uf = UF_HOST;\n        break;\n\n      case s_req_path:\n        uf = UF_PATH;\n        break;\n\n      case s_req_query_string:\n        uf = UF_QUERY;\n        break;\n\n      case s_req_fragment:\n        uf = UF_FRAGMENT;\n        break;\n\n      default:\n        assert(!\"Unexpected state\");\n        return 1;\n    }\n\n    /* Nothing's changed; soldier on */\n    if (uf == old_uf) {\n      u->field_data[uf].len++;\n      continue;\n    }\n\n    u->field_data[uf].off = p - buf;\n    u->field_data[uf].len = 1;\n\n    u->field_set |= (1 << uf);\n    old_uf = uf;\n  }\n\n  /* host must be present if there is a schema */\n  /* parsing http:///toto will fail */\n  if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) {\n    if (http_parse_host(buf, u, found_at) != 0) {\n      return 1;\n    }\n  }\n\n  /* CONNECT requests can only contain \"hostname:port\" */\n  if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {\n    return 1;\n  }\n\n  if (u->field_set & (1 << UF_PORT)) {\n    /* Don't bother with endp; we've already validated the string */\n    unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);\n\n    /* Ports have a max value of 2^16 */\n    if (v > 0xffff) {\n      return 1;\n    }\n\n    u->port = (uint16_t) v;\n  }\n\n  return 0;\n}\n\nvoid ICACHE_FLASH_ATTR http_parser_pause(http_parser *parser, int paused) {\n  /* Users should only be pausing/unpausing a parser that is not in an error\n   * state. In non-debug builds, there's not much that we can do about this\n   * other than ignore it.\n   */\n  if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||\n      HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {\n    SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);\n  } else {\n    assert(0 && \"Attempting to pause parser in error state\");\n  }\n}\n\nint ICACHE_FLASH_ATTR http_body_is_final(const struct http_parser *parser) {\n    return parser->state == s_message_done;\n}\n\nunsigned long ICACHE_FLASH_ATTR http_parser_version(void) {\n  return HTTP_PARSER_VERSION_MAJOR * 0x10000 |\n         HTTP_PARSER_VERSION_MINOR * 0x00100 |\n         HTTP_PARSER_VERSION_PATCH * 0x00001;\n}"
  },
  {
    "path": "app/http/http_parser.h",
    "content": "/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * 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 DEALINGS\n * IN THE SOFTWARE.\n */\n#ifndef http_parser_h\n#define http_parser_h\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Also update SONAME in the Makefile whenever you change these. */\n#define HTTP_PARSER_VERSION_MAJOR 2\n#define HTTP_PARSER_VERSION_MINOR 4\n#define HTTP_PARSER_VERSION_PATCH 2\n\n#include <sys/types.h>\n#include \"c_stdint.h\"\n\n\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"user_interface.h\"\n\n/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run\n * faster\n */\n#ifndef HTTP_PARSER_STRICT\n# define HTTP_PARSER_STRICT 0\n#endif\n\n/* Maximium header size allowed. If the macro is not defined\n * before including this header then the default is used. To\n * change the maximum header size, define the macro in the build\n * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove\n * the effective limit on the size of the header, define the macro\n * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)\n */\n#ifndef HTTP_MAX_HEADER_SIZE\n# define HTTP_MAX_HEADER_SIZE (80*1024)\n#endif\n\ntypedef struct http_parser http_parser;\ntypedef struct http_parser_settings http_parser_settings;\n\n\n/* Callbacks should return non-zero to indicate an error. The parser will\n * then halt execution.\n *\n * The one exception is on_headers_complete. In a HTTP_RESPONSE parser\n * returning '1' from on_headers_complete will tell the parser that it\n * should not expect a body. This is used when receiving a response to a\n * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:\n * chunked' headers that indicate the presence of a body.\n *\n * http_data_cb does not return data chunks. It will be called arbitrarily\n * many times for each string. E.G. you might get 10 callbacks for \"on_url\"\n * each providing just a few characters more data.\n */\ntypedef int (*http_data_cb) (http_parser*, const char *at, size_t length);\ntypedef int (*http_cb) (http_parser*);\n\n\n/* Request Methods */\n#define HTTP_METHOD_MAP(XX)         \\\n  XX(0,  DELETE,      DELETE)       \\\n  XX(1,  GET,         GET)          \\\n  XX(2,  HEAD,        HEAD)         \\\n  XX(3,  POST,        POST)         \\\n  XX(4,  PUT,         PUT)          \\\n  /* pathological */                \\\n  XX(5,  CONNECT,     CONNECT)      \\\n  XX(6,  OPTIONS,     OPTIONS)      \\\n  XX(7,  TRACE,       TRACE)        \\\n  /* webdav */                      \\\n  XX(8,  COPY,        COPY)         \\\n  XX(9,  LOCK,        LOCK)         \\\n  XX(10, MKCOL,       MKCOL)        \\\n  XX(11, MOVE,        MOVE)         \\\n  XX(12, PROPFIND,    PROPFIND)     \\\n  XX(13, PROPPATCH,   PROPPATCH)    \\\n  XX(14, SEARCH,      SEARCH)       \\\n  XX(15, UNLOCK,      UNLOCK)       \\\n  /* subversion */                  \\\n  XX(16, REPORT,      REPORT)       \\\n  XX(17, MKACTIVITY,  MKACTIVITY)   \\\n  XX(18, CHECKOUT,    CHECKOUT)     \\\n  XX(19, MERGE,       MERGE)        \\\n  /* upnp */                        \\\n  XX(20, MSEARCH,     M-SEARCH)     \\\n  XX(21, NOTIFY,      NOTIFY)       \\\n  XX(22, SUBSCRIBE,   SUBSCRIBE)    \\\n  XX(23, UNSUBSCRIBE, UNSUBSCRIBE)  \\\n  /* RFC-5789 */                    \\\n  XX(24, PATCH,       PATCH)        \\\n  XX(25, PURGE,       PURGE)        \\\n  /* CalDAV */                      \\\n  XX(26, MKCALENDAR,  MKCALENDAR)   \\\n\nenum http_method\n  {\n#define XX(num, name, string) HTTP_##name = num,\n  HTTP_METHOD_MAP(XX)\n#undef XX\n  };\n\n\nenum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };\n\n\n/* Flag values for http_parser.flags field */\nenum flags\n  { F_CHUNKED               = 1 << 0\n  , F_CONNECTION_KEEP_ALIVE = 1 << 1\n  , F_CONNECTION_CLOSE      = 1 << 2\n  , F_CONNECTION_UPGRADE    = 1 << 3\n  , F_TRAILING              = 1 << 4\n  , F_UPGRADE               = 1 << 5\n  , F_SKIPBODY              = 1 << 6\n  };\n\n\n/* Map for errno-related constants\n * \n * The provided argument should be a macro that takes 2 arguments.\n */\n#define HTTP_ERRNO_MAP(XX)                         \\\n  /* No error */                                                     \\\n  XX(OK, \"success\")                                                  \\\n                                                                     \\\n  /* Callback-related errors */                                      \\\n  XX(CB_message_begin, \"the on_message_begin callback failed\")       \\\n  XX(CB_url, \"the on_url callback failed\")                           \\\n  XX(CB_header_field, \"the on_header_field callback failed\")         \\\n  XX(CB_header_value, \"the on_header_value callback failed\")         \\\n  XX(CB_headers_complete, \"the on_headers_complete callback failed\") \\\n  XX(CB_body, \"the on_body callback failed\")                         \\\n  XX(CB_message_complete, \"the on_message_complete callback failed\") \\\n  XX(CB_status, \"the on_status callback failed\")                     \\\n                                                                     \\\n  /* Parsing-related errors */                                       \\\n  XX(INVALID_EOF_STATE, \"stream ended at an unexpected time\")        \\\n  XX(HEADER_OVERFLOW,                                                \\\n     \"too many header bytes seen; overflow detected\")                \\\n  XX(CLOSED_CONNECTION,                                              \\\n     \"data received after completed connection: close message\")      \\\n  XX(INVALID_VERSION, \"invalid HTTP version\")                        \\\n  XX(INVALID_STATUS, \"invalid HTTP status code\")                     \\\n  XX(INVALID_METHOD, \"invalid HTTP method\")                          \\\n  XX(INVALID_URL, \"invalid URL\")                                     \\\n  XX(INVALID_HOST, \"invalid host\")                                   \\\n  XX(INVALID_PORT, \"invalid port\")                                   \\\n  XX(INVALID_PATH, \"invalid path\")                                   \\\n  XX(INVALID_QUERY_STRING, \"invalid query string\")                   \\\n  XX(INVALID_FRAGMENT, \"invalid fragment\")                           \\\n  XX(LF_EXPECTED, \"LF character expected\")                           \\\n  XX(INVALID_HEADER_TOKEN, \"invalid character in header\")            \\\n  XX(INVALID_CONTENT_LENGTH,                                         \\\n     \"invalid character in content-length header\")                   \\\n  XX(INVALID_CHUNK_SIZE,                                             \\\n     \"invalid character in chunk size header\")                       \\\n  XX(INVALID_CONSTANT, \"invalid constant string\")                    \\\n  XX(INVALID_INTERNAL_STATE, \"encountered unexpected internal state\")\\\n  XX(STRICT, \"strict mode assertion failed\")                         \\\n  XX(PAUSED, \"parser is paused\")                                     \\\n  XX(UNKNOWN, \"an unknown error occurred\")\n\n\n/* Define HPE_* values for each errno value above */\n#define HTTP_ERRNO_GEN(n, s) HPE_##n,\nenum http_errno {\n  HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)\n};\n#undef HTTP_ERRNO_GEN\n\n\n/* Get an http_errno value from an http_parser */\n#define HTTP_PARSER_ERRNO(p)            ((enum http_errno) (p)->http_errno)\n\n\nstruct http_parser {\n  /** PRIVATE **/\n  unsigned int type : 2;         /* enum http_parser_type */\n  unsigned int flags : 7;        /* F_* values from 'flags' enum; semi-public */\n  unsigned int state : 7;        /* enum state from http_parser.c */\n  unsigned int header_state : 8; /* enum header_state from http_parser.c */\n  unsigned int index : 8;        /* index into current matcher */\n\n  uint32_t nread;          /* # bytes read in various scenarios */\n  uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */\n\n  /** READ-ONLY **/\n  unsigned short http_major;\n  unsigned short http_minor;\n  unsigned int status_code : 16; /* responses only */\n  unsigned int method : 8;       /* requests only */\n  unsigned int http_errno : 7;\n\n  /* 1 = Upgrade header was present and the parser has exited because of that.\n   * 0 = No upgrade header present.\n   * Should be checked when http_parser_execute() returns in addition to\n   * error checking.\n   */\n  unsigned int upgrade : 1;\n\n  /** PUBLIC **/\n  void *data; /* A pointer to get hook to the \"connection\" or \"socket\" object */\n};\n\n\nstruct http_parser_settings {\n  http_cb      on_message_begin;\n  http_data_cb on_url;\n  http_data_cb on_status;\n  http_data_cb on_header_field;\n  http_data_cb on_header_value;\n  http_cb      on_headers_complete;\n  http_data_cb on_body;\n  http_cb      on_message_complete;\n};\n\n\nenum http_parser_url_fields\n  { UF_SCHEMA           = 0\n  , UF_HOST             = 1\n  , UF_PORT             = 2\n  , UF_PATH             = 3\n  , UF_QUERY            = 4\n  , UF_FRAGMENT         = 5\n  , UF_USERINFO         = 6\n  , UF_MAX              = 7\n  };\n\n\n/* Result structure for http_parser_parse_url().\n *\n * Callers should index into field_data[] with UF_* values iff field_set\n * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and\n * because we probably have padding left over), we convert any port to\n * a uint16_t.\n */\nstruct http_parser_url {\n  uint16_t field_set;           /* Bitmask of (1 << UF_*) values */\n  uint16_t port;                /* Converted UF_PORT string */\n\n  struct {\n    uint16_t off;               /* Offset into buffer in which field starts */\n    uint16_t len;               /* Length of run in buffer */\n  } field_data[UF_MAX];\n};\n\n\n/* Returns the library version. Bits 16-23 contain the major version number,\n * bits 8-15 the minor version number and bits 0-7 the patch level.\n * Usage example:\n *\n *   unsigned long version = http_parser_version();\n *   unsigned major = (version >> 16) & 255;\n *   unsigned minor = (version >> 8) & 255;\n *   unsigned patch = version & 255;\n *   printf(\"http_parser v%u.%u.%u\\n\", major, minor, patch);\n */\nunsigned long ICACHE_FLASH_ATTR http_parser_version(void);\n\nvoid ICACHE_FLASH_ATTR http_parser_init(http_parser *parser, enum http_parser_type type);\n\n\n/* Initialize http_parser_settings members to 0\n */\nvoid ICACHE_FLASH_ATTR http_parser_settings_init(http_parser_settings *settings);\n\n\n/* Executes the parser. Returns number of parsed bytes. Sets\n * `parser->http_errno` on error. */\nsize_t ICACHE_FLASH_ATTR http_parser_execute(http_parser *parser,\n                           const http_parser_settings *settings,\n                           const char *data,\n                           size_t len);\n\n\n/* If http_should_keep_alive() in the on_headers_complete or\n * on_message_complete callback returns 0, then this should be\n * the last message on the connection.\n * If you are the server, respond with the \"Connection: close\" header.\n * If you are the client, close the connection.\n */\nint ICACHE_FLASH_ATTR http_should_keep_alive(const http_parser *parser);\n\n/* Returns a string version of the HTTP method. */\nconst char *ICACHE_FLASH_ATTR http_method_str(enum http_method m);\n\n/* Return a string name of the given error */\nconst char * ICACHE_FLASH_ATTR http_errno_name(enum http_errno err);\n\n/* Return a string description of the given error */\nconst char * ICACHE_FLASH_ATTR http_errno_description(enum http_errno err);\n\n/* Parse a URL; return nonzero on failure */\nint ICACHE_FLASH_ATTR http_parser_parse_url(const char *buf, size_t buflen,\n                          int is_connect,\n                          struct http_parser_url *u);\n\n/* Pause or un-pause the parser; a nonzero value pauses */\nvoid ICACHE_FLASH_ATTR http_parser_pause(http_parser *parser, int paused);\n\n/* Checks if this is the final chunk of the body. */\nint ICACHE_FLASH_ATTR http_body_is_final(const http_parser *parser);\n\n#ifdef __cplusplus\n}\n#endif\n#endif"
  },
  {
    "path": "app/http/http_process.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"c_types.h\"\n#include \"user_interface.h\"\n#include \"espconn.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"c_stdio.h\"\n\n#include \"espconn.h\"\n#include \"http_parser.h\"\n#include \"http_process.h\"\n#include \"http_server.h\"\n#include \"http_helper.h\"\n#include \"user_config.h\"\n#include \"cgi.h\"\n\nstatic http_connection connection_poll[MAX_CONNECTIONS];\n\nvoid http_execute_cgi(http_connection *conn){\n\n\tif (conn->espConnection==NULL)\n\t\treturn;\n\n\tif(conn->cgi.execute==NULL)\n\t\treturn;\n\n\tconn->cgi.execute(conn);\t\t\n\n}\n\nint ICACHE_FLASH_ATTR http_transmit(http_connection *c){\n\n\tNODE_DBG(\"Transmit Buffer\");\n\n\tint len = (c->output.bufferPos - c->output.buffer);\n\tif(len>0 && len <= HTTP_BUFFER_SIZE){\n\n\t\t\tespconn_send(c->espConnection, (uint8_t*)(c->output.buffer),len);\t\t\t\n\t}\n\telse{\n\t\tNODE_DBG(\"Wrong transmit size %d\",len);\n\t}\n\n\t//free buffer\n\thttp_reset_buffer(c);\n\n\treturn len;\n}\n\nint ICACHE_FLASH_ATTR http_nwrite(http_connection *c,const char * message,size_t size){\n\n\tint rem;\n\n\t\t\n\trem = c->output.buffer + HTTP_BUFFER_SIZE - c->output.bufferPos;\n\t//NODE_DBG(\"Response write %d, Buffer rem %d , buffer add : %p\",size,rem,c->response.buffer);\n\n\n\tif(rem < size && c->cgi.function!=cgi_transmit){\n\t\tNODE_DBG(\"Buffer Overflow\");\n\n\t\t//copy what's possible\n\t\tos_memcpy(c->output.bufferPos,message,rem);\n\t\tmessage+=rem; //advance message\n\t\tsize-=rem; //adjust size\n\t\tc->output.bufferPos+=rem; //mark buffer pos\n\n\t\tstruct cgi_transmit_arg *transmit_cgi = (struct cgi_transmit_arg*)os_malloc(sizeof(struct cgi_transmit_arg));\n\t\tos_memcpy(&transmit_cgi->previous_cgi,&c->cgi,sizeof(cgi_struct));\n\t\tc->cgi.function=cgi_transmit;\n\n\t\ttransmit_cgi->data = (uint8_t*)os_malloc(size);\n\t\tos_memcpy(transmit_cgi->data,message,size);\n\t\ttransmit_cgi->len=size;\n\t\ttransmit_cgi->dataPos=transmit_cgi->data;\n\n\t\tc->cgi.data = transmit_cgi;\n\t\tc->cgi.done=0;\n\n\t\t//http_transmit(c);\n\t\t//goto process; //restart;\n\n\t}else{\n\t\tos_memcpy(c->output.bufferPos,message,size);\n\t\tc->output.bufferPos+=size;\n\t}\t\n\n\treturn 1;\n}\n\nint ICACHE_FLASH_ATTR http_write(http_connection *c,const char * message){\n\t\n\tsize_t len = strlen(message);\n\n\treturn http_nwrite(c,message,len);\n\n}\n\n\n\n// HEADER RELATED FUNCTIONS -------------------------------------------------------\n// \n//\nheader * ICACHE_FLASH_ATTR http_get_header(http_connection *conn,const char* header){\n\n\tint i=0;\n\twhile(conn->headers[i].key!=NULL){\n\n\t\tif(os_strcmp(conn->headers[i].key,header)==0)\n\t\t{\n\t\t\tif(conn->headers[i].value!=NULL)\n\t\t\t\treturn &(conn->headers[i]);\n\t\t\telse \n\t\t\t\treturn NULL;\n\t\t}\n\n\t\ti++;\n\t}\n\n\treturn NULL;\n}\n\nvoid ICACHE_FLASH_ATTR http_set_save_header(http_connection *conn,const char* header){\n\n\tNODE_DBG(\"http_parser will save header :%s\",header);\n\n\tint j=0;\n\twhile(conn->headers[j].key!=NULL && j< MAX_HEADERS) j++;\n\tif(j==MAX_HEADERS) return;\n\n\tconn->headers[j].key=(char*)header;\n\tconn->headers[j].save=0;\n\n}\n\nvoid ICACHE_FLASH_ATTR http_set_save_body(http_connection *conn){\n\n\tNODE_DBG(\"http_parser will save body\");\n\n\tconn->body.save=1;\n\n\t//make sure body is free\n\tif(conn->body.data!=NULL){\n\t\tos_free(conn->body.data);\n\t\tconn->body.data=NULL;\n\t}\n}\n\n\n\n\nchar * ICACHE_FLASH_ATTR http_url_get_field(http_connection *c,enum http_parser_url_fields field){\n\n\tif(c->url_parsed.field_set & (1<<field)){\n\n\t\tchar * start = c->url + c->url_parsed.field_data[field].off;\n\t\tchar * end = start + c->url_parsed.field_data[field].len -1;\n\t\tend++;\n\t\t*end=0;\n\n\t\tif(*start==0){\n\t\t\tif(field==UF_PATH)\n\t\t\t\t*start='/';\n\n\t\t}\n\n\t\treturn start;\n\t}\n\telse\n\t\treturn NULL;\n\n}\n\nchar * ICACHE_FLASH_ATTR http_url_get_query_param(http_connection *c,char* param){\n\tNODE_DBG(\"http_url_get_query_param\");\n\tif(!(c->url_parsed.field_set & (1<<UF_QUERY))) //return null if there's no query at all\n\t\treturn NULL;\n\n\n\t//find field\n\tchar *start = c->url + c->url_parsed.field_data[UF_QUERY].off;\n\tchar * end = start + c->url_parsed.field_data[UF_QUERY].len -1;\n\n\tchar *param_search = (char*)os_malloc(strlen(param)+2);\n\tos_strcpy(param_search,param);\n\tos_strcat(param_search,\"=\");\n\n\tNODE_DBG(\"search for : %s\",param_search);\n\n\tchar *ret=NULL;\n\n\tstart--; //to start at ?\n\twhile(start<=end){\n\n\t\tNODE_DBG(\"char : %c\",*start);\n\n\t\tif(*start == '?' || *start == '&' || *start=='\\0'){\n\n\t\t\tNODE_DBG(\"Is match?\");\n\n\t\t\tstart++;\n\t\t\t//check param name, case insensitive\n\t\t\tif(os_strcasecmp(param_search,start)==0){\n\t\t\t\tNODE_DBG(\"yes\");\n\t\t\t\t//match\n\t\t\t\tstart +=strlen(param_search);\n\n\t\t\t\tret = start;\n\n\t\t\t\t//0 end string\t\t\t\t\n\t\t\t\twhile(*start!='\\0' && *start!='&')\n\t\t\t\t\tstart++;\n\t\t\t\t\n\t\t\t\t*start='\\0';\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tstart++;\n\n\t}\n\n\tos_free(param_search);\n\treturn ret;\n}\n\n\n\n\nchar * ICACHE_FLASH_ATTR http_url_get_host(http_connection *c){\n\treturn http_url_get_field(c,UF_HOST);\n}\nchar * ICACHE_FLASH_ATTR http_url_get_path(http_connection *c){\n\treturn http_url_get_field(c,UF_PATH);\n}\nchar * ICACHE_FLASH_ATTR http_url_get_query(http_connection *c){\n\treturn http_url_get_field(c,UF_QUERY);\n}\n\n\nvoid ICACHE_FLASH_ATTR http_parse_url(http_connection *c){\n\t\n\tmemset(&c->url_parsed,0,sizeof(struct http_parser_url));\n\n\thttp_parser_parse_url(\n\t\t(const char *)c->url,\n\t\tstrlen(c->url),\n\t\t0,\n\t\t&c->url_parsed\n\t\t);\n\n\t#ifdef DEVELOP_VERSION\n\n\t\tNODE_DBG(\"Parse URL : %s\",c->url);\n\n\t\tNODE_DBG(\"\\tPORT: %d\",c->url_parsed.port);\t\t\t\n\n\t\tif(c->url_parsed.field_set & (1<<UF_SCHEMA)){\n\t\t\tNODE_DBG(\"\\tSCHEMA: \");\n\t\t\tnprintf(c->url + c->url_parsed.field_data[UF_SCHEMA].off,c->url_parsed.field_data[UF_SCHEMA].len);\n\t\t}\n\t\tif(c->url_parsed.field_set & (1<<UF_HOST)){\n\t\t\tNODE_DBG(\"\\tHOST: \");\n\t\t\tnprintf(c->url + c->url_parsed.field_data[UF_HOST].off,c->url_parsed.field_data[UF_HOST].len);\n\t\t}\n\t\tif(c->url_parsed.field_set & (1<<UF_PORT)){\n\t\t\tNODE_DBG(\"\\tPORT: \");\n\t\t\tnprintf(c->url + c->url_parsed.field_data[UF_PORT].off,c->url_parsed.field_data[UF_PORT].len);\n\t\t}\n\t\tif(c->url_parsed.field_set & (1<<UF_PATH)){\n\t\t\tNODE_DBG(\"\\tPATH: \");\n\t\t\tnprintf(c->url + c->url_parsed.field_data[UF_PATH].off,c->url_parsed.field_data[UF_PATH].len);\n\t\t}\n\t\tif(c->url_parsed.field_set & (1<<UF_QUERY)){\n\t\t\tNODE_DBG(\"\\tQUERY: \");\n\t\t\tnprintf(c->url + c->url_parsed.field_data[UF_QUERY].off,c->url_parsed.field_data[UF_QUERY].len);\n\t\t}\n\t\tif(c->url_parsed.field_set & (1<<UF_FRAGMENT)){\n\t\t\tNODE_DBG(\"\\tFRAGMENT: \");\n\t\t\tnprintf(c->url + c->url_parsed.field_data[UF_FRAGMENT].off,c->url_parsed.field_data[UF_FRAGMENT].len);\n\t\t}\n\t\tif(c->url_parsed.field_set & (1<<UF_USERINFO)){\n\t\t\tNODE_DBG(\"\\tUSER INFO: \");\n\t\t\tnprintf(c->url + c->url_parsed.field_data[UF_USERINFO].off,c->url_parsed.field_data[UF_USERINFO].len);\n\t\t}\n\n\n\t#endif\n\n}\n\n//Parser callbacks\nstatic int ICACHE_FLASH_ATTR on_message_begin(http_parser *parser){\n\tNODE_DBG(\"http_parser message begin\");\n\t\n\t//nothing to do here\n\treturn 0;\n}\n\nstatic int ICACHE_FLASH_ATTR on_url(http_parser *parser, const char *url, size_t length)\n{\t\n\tNODE_DBG(\"\\nhttp_parser url: \");\n\tnprintf(url,length);\n\n\tNODE_DBG(\"http_parser method: %d\",parser->method);\n\t\t\n\n\t//grab the connection\n\thttp_connection * conn = (http_connection *)parser->data;\n\n\tconn->state=HTTPD_STATE_ON_URL; //set state\n\n\tos_memcpy(conn->url,url,length); //copy url to connection info\n\tconn->url[length]=0; //null terminate string\n\n\thttp_parse_url(conn);\n\n\t//execute cgi\n\thttp_execute_cgi(conn);\n\n\treturn 0;\n}\n\nstatic int ICACHE_FLASH_ATTR on_status(http_parser *parser, const char *url, size_t length)\n{\t\n\tNODE_DBG(\"http_parser status: \");\n\tnprintf(url,length);\n\n\t//grab the connection\n\thttp_connection * conn = (http_connection *)parser->data;\n\n\tconn->state=HTTPD_STATE_ON_STATUS; //set state\n\n\t//execute cgi again\n\thttp_execute_cgi(conn);\n\n\treturn 0;\n}\n\n\nstatic int ICACHE_FLASH_ATTR on_header_field(http_parser *parser, const char *at, size_t length)\n{\n\tNODE_DBG(\"http_parser header: \");\n\tnprintf(at,length);\n\n\t//grab the connection\n\thttp_connection * conn = (http_connection *)parser->data;\n\n\tint i=0;\n\twhile(conn->headers[i].key!=NULL){\t\t\n\t\tif(os_strncmp(conn->headers[i].key,at,length)==0){\n\t\t\tNODE_DBG(\"marking header to save\");\n\t\t\t//match header\t\t\t\n\t\t\t//turn on save header\t\t\t\n\t\t\tconn->headers[i].save=1;\n\n\t\t\tbreak;\n\t\t}\n\n\t\ti++;\n\t}\n\t\n\treturn 0;\n}\n\nstatic int ICACHE_FLASH_ATTR on_header_value(http_parser *parser, const char *at, size_t length)\n{\n\tNODE_DBG(\"http_parser header value: \");\n\tnprintf(at,length);\n\t\n\t//grab the connection\n\thttp_connection * conn = (http_connection *)parser->data;\n\n\tint i=0;\n\twhile(conn->headers[i].key!=NULL){\t\t\n\t\tif(conn->headers[i].save==1){\n\t\t\tNODE_DBG(\"saving header\");\n\n\t\t\tconn->headers[i].value=(char *) os_malloc(length+1);\n\t\t\tos_memcpy(conn->headers[i].value,at,length);\n\t\t\tconn->headers[i].value[length]=0; //terminate string;\n\n\t\t\tconn->headers[i].save=0;\n\n\t\t\tbreak;\n\n\t\t\t\n\t\t}\n\n\t\ti++;\n\t}\n\t\n\treturn 0;\n}\n\nstatic int ICACHE_FLASH_ATTR on_headers_complete(http_parser *parser){\n\tNODE_DBG(\"\\nhttp_parser headers complete\");\n\n\t//grab the connection\n\thttp_connection * conn = (http_connection *)parser->data;\n\n\tconn->state = HTTPD_STATE_HEADERS_END; //set state\n\n\t//execute cgi again\n\thttp_execute_cgi(conn);\n\t\n}\n\nstatic int ICACHE_FLASH_ATTR on_body(http_parser *parser, const char *at, size_t length)\n{\n\tNODE_DBG(\"\\nhttp_parser body: \");\n\tnprintf(at,length);\n\n\t//grab the connection\n\thttp_connection * conn = (http_connection *)parser->data;\n\n\tconn->state = HTTPD_STATE_ON_BODY; //set state\n\n\tif(conn->body.save){\n\n\t\tif(conn->body.data==NULL){\n\n\t\t\tNODE_DBG(\"saving body len %d\",length);\n\n\t\t\tconn->body.data = (char *) os_malloc(length+1);\t\t\n\t\t\tos_memcpy(conn->body.data,at,length);\t\n\t\t\tconn->body.len = length;\n\t\t\tconn->body.data[length]=0;\n\t\t}\n\t\telse{\n\t\t\t//assuming body can come in different tcp packets, this callback will be called\n\t\t\t//more than once\n\t\t\t\n\t\t\tNODE_DBG(\"appending body len %d\",length);\n\n\t\t\tsize_t newLenght = conn->body.len+length;\n\t\t\tchar * newBuffer = (char *) os_malloc(newLenght+1);\n\t\t\tos_memcpy(newBuffer,conn->body.data,conn->body.len); //copy previous data\n\t\t\tos_memcpy(newBuffer+conn->body.len,at,length); //copy new data\n\t\t\tos_free(conn->body.data); //free previous\n\t\t\tconn->body.data=newBuffer;\n\t\t\tconn->body.len=newLenght;\n\t\t\tconn->body.data[newLenght]=0;\n\t\t}\n\n\t}\n\t\n\t//execute cgi again\n\thttp_execute_cgi(conn);\n\n\treturn 0;\t\n}\n\n//special callback like function to pass ws data to cgi\nstatic int ICACHE_FLASH_ATTR on_websocket_data(http_parser *parser, char *data, size_t length)\n{\n\tNODE_DBG(\"\\non_websocket_data : \");\n\tint i;\n\tfor(i=0;i<length;i++)\n\t\tos_printf(\"%02X\",data[i]);\n\tos_printf(\"\\r\\n\");\n\n\t//grab the connection\n\thttp_connection * conn = (http_connection *)parser->data;\n\n\tconn->state = HTTPD_STATE_WS_DATA; //set state\n\n\t\n\tconn->body.data = (char *)data;\n\tconn->body.len = length;\t\n\t\n\t//execute cgi again\n\thttp_execute_cgi(conn);\n\n\tconn->body.data=NULL;\n\tconn->body.len=0;\n\n\treturn 0;\t\n}\n\n\n\nstatic int ICACHE_FLASH_ATTR on_message_complete(http_parser *parser){\n\n\tNODE_DBG(\"\\nhttp_parser message complete\");\n\n\t//grab the connection\n\thttp_connection * conn = (http_connection *)parser->data;\n\n\tconn->state = HTTPD_STATE_BODY_END; //set state\n\n\t//execute cgi again\n\thttp_execute_cgi(conn);\t\t\n\n\t//free body\n\tif(conn->body.save==1 && conn->body.data!=NULL){\n\t\tNODE_DBG(\"freeing body memory\");\n\t\tos_free(conn->body.data);\n\t\tconn->body.len=0;\t\n\t}\t\n\n\treturn 0;\n}\n\n//Looks up the connection for a specific esp connection\nstatic http_connection ICACHE_FLASH_ATTR *http_process_find_connection(void *arg) {\n\tint i;\n\n\tif(arg==0){\n\t\tNODE_DBG(\"http_process_find_connection: Couldn't find connection for %p\", arg);\n\t\treturn NULL;\n\t}\n\n\tfor(i=0;i<MAX_CONNECTIONS;i++) if(connection_poll[i].espConnection==arg) break;\n\n\tif(i<MAX_CONNECTIONS){\n\t\treturn &connection_poll[i];\n\t}else{\n\t\tNODE_DBG(\"http_process_find_connection: Couldn't find connection for %p\", arg);\n\t\treturn NULL; //WtF?\n\t}\n\t\t\n}\n\nvoid ICACHE_FLASH_ATTR http_process_free_connection(http_connection *conn){\n\n\thttp_reset_buffer(conn);\n\n\tconn->espConnection=NULL;\t\n\t\n\tconn->cgi.function=NULL;\n\tconn->cgi.data=NULL;\n\tconn->cgi.argument=NULL;\n\n\t//free headers\t\n\tint j=0;\n\twhile(j<MAX_HEADERS){\n\t\t\n\t\tif(conn->headers[j].value!=NULL \n\t\t\t&& (conn->headers[j].value!=conn->headers[j].key))\n\t\t{\n\t\t\tos_free(conn->headers[j].value);\t\n\t\t\tconn->headers[j].value=NULL;\n\t\t}\n\t\tconn->headers[j].key=NULL;\n\n\t\tj++;\n\t}\n\n\t//free buffer\n\tos_free(conn->output.buffer);\n}\n\n//esp conn callbacks\nstatic void ICACHE_FLASH_ATTR http_process_sent_cb(void *arg) {\n\n\tNODE_DBG(\"\\nhttp_process_sent_cb, conn %p\",arg);\t\n\t\n\thttp_connection *conn = http_process_find_connection(arg);\n\t\n\tif(conn==NULL)\n\t\t\treturn;\t\n\t\n\tif (conn->cgi.done==1) { //Marked for destruction?\n\t\tNODE_DBG(\"Conn %p is done. Closing.\", conn->espConnection);\n\t\tespconn_disconnect(conn->espConnection);\n\t\thttp_process_free_connection(conn);\t\t\t\t\n\t\treturn; //No need to execute cgi again\n\t}//\n\t\n\tif(conn->parser.upgrade){\n\t\tconn->state = HTTPD_STATE_WS_DATA_SENT; //set state\n\t}\t\n\n\thttp_execute_cgi(conn);\t\t\n\t\t\n}\n\n//Callback called when there's data available on a socket.\nstatic void ICACHE_FLASH_ATTR http_process_received_cb(void *arg, char *data, unsigned short len) {\n\tNODE_DBG(\"\\nhttp_process_received_cb, len: %d\",len);\n\n\thttp_connection *conn = http_process_find_connection(arg);\n\tif(conn==NULL){\n\t\tespconn_disconnect(arg);\n\t\treturn;\n\t}\n\n\t//pass data to http_parser\t\n\tsize_t nparsed = http_parser_execute(\n\t\t&(conn->parser),\n\t\t&(conn->parser_settings),\n\t\tdata,\n\t\tlen);\n\n\tif (conn->parser.upgrade) {\n  \t\t/* handle new protocol */\n\t\ton_websocket_data(&conn->parser,data,len);\n\n\t} else if (nparsed != len) {\n\t  /* Handle error. Usually just close the connection. */\n\t\tespconn_disconnect(conn->espConnection);\n\t\thttp_process_free_connection(conn);\t\n\t}\n\t\n}\n\n\nstatic void ICACHE_FLASH_ATTR http_process_disconnect_cb(void *arg) {\n\n\tNODE_DBG(\"Disconnect conn=%p\",arg);\n\n\n\thttp_connection *conn = http_process_find_connection(arg);\n\tif(conn!=NULL){\n\n\t\t//is it a client connection?\n\t\tif(conn->espConnection== &conn->client_connection){\t\t\t\n\t\t\t//tell parser about EOF\t\t\t\n\t\t\thttp_parser_execute(\n\t\t\t\t&(conn->parser),\n\t\t\t\t&(conn->parser_settings),\n\t\t\t\tNULL,\n\t\t\t\t0);\n\t\t}\n\n\t\tif (conn->parser.upgrade) {\n\t\t\tconn->state=HTTPD_STATE_WS_CLIENT_DISCONNECT;\n\t\t\thttp_execute_cgi(conn);\n\t\t}\n\n\t\thttp_process_free_connection(conn);\n\t}\n\telse{\n\n\t\t//find connections that should be closed\n\t\tint i;\n\t\tfor(i=0;i<MAX_CONNECTIONS;i++)\n\t\t{\n\t\t\tstruct espconn *conn = connection_poll[i].espConnection;\n\n\t\t\tif(conn!=NULL){\n\t\t\t\tif(conn->state==ESPCONN_NONE || conn->state >=ESPCONN_CLOSE){\n\t\t\t\t//should close\n\n\t\t\t\t//is it a client connection? If yes, don't free\n\t\t\t\tif(&connection_poll[i].client_connection != connection_poll[i].espConnection)\n\t\t\t\t{\n\t\t\t\t\thttp_process_free_connection(&connection_poll[i]);\n\t\t\t\t}\t\t\t\t\n\t\t\t\t\t\n\t\t\t}\n\t\t\t\t\t\n\t\t\t}\n\t\t}\n\n\n\t}\n\n\t\n\n}\n\n\nstatic void ICACHE_FLASH_ATTR http_process_reconnect_cb(void *arg, sint8 err) {\n\t//some error\n\n\tNODE_DBG(\"Reconnect conn=%p err %d\",arg,err);\t\n\n\tstruct espconn * conn = (struct espconn *)arg;\n\tconn->state=ESPCONN_CLOSE; // make sure of that \t\t\n\n\thttp_process_disconnect_cb(arg);\t\n}\n\nhttp_connection ICACHE_FLASH_ATTR * http_new_connection(uint8_t in,struct espconn *conn){\n\n\tint i;\n\t//Find empty connection in pool\n\tfor (i=0; i<MAX_CONNECTIONS; i++) if (connection_poll[i].espConnection==NULL) break;\n\t\n\n\tif (i>=MAX_CONNECTIONS) {\n\t\tNODE_DBG(\"Connection pool overflow!\");\t\n\n\t\tif(conn!=NULL){\t\t\t\n\t\t\tespconn_disconnect(conn);\n\t\t}\n\n\t\treturn;\n\t}\t\n\n\tNODE_DBG(\"\\nNew connection, conn=%p, pool slot %d\", conn, i);\n\n\tif(conn!=NULL){\t\t\n\t\tconnection_poll[i].espConnection=conn;\n\t\tconnection_poll[i].espConnection->reverse=&connection_poll[i];\n\t}\n\n\t//allocate buffer\n\tconnection_poll[i].output.buffer = (uint8_t *)os_zalloc(HTTP_BUFFER_SIZE);\n\n\t//zero headers again- for sanity\n\tint j=0;\n\twhile(j<MAX_HEADERS){\n\n\t\tif(connection_poll[i].headers[j].value!=NULL\n\t\t\t&& (connection_poll[i].headers[j].value!=connection_poll[i].headers[j].key)){\n\t\t\tos_free(connection_poll[i].headers[j].value);\t\n\t\t\tconnection_poll[i].headers[j].value=NULL;\n\t\t}\n\t\tconnection_poll[i].headers[j].key=NULL;\n\t\t\n\t\tj++;\n\t}\n\n\t//mark cgi as not done\n\tconnection_poll[i].cgi.done=0;\n\t\n\t//free response buffer again\n\thttp_reset_buffer(&connection_poll[i]);\n\t\t\n\t//init body\n\tconnection_poll[i].body.len=0;\n\tconnection_poll[i].body.save=0;\n\tconnection_poll[i].body.data=NULL;\n\n\t//reset parser\t\n\thttp_parser_settings_init(&(connection_poll[i].parser_settings));\n\tconnection_poll[i].parser_settings.on_message_begin=on_message_begin;\n\tconnection_poll[i].parser_settings.on_url=on_url;\n\tconnection_poll[i].parser_settings.on_header_field=on_header_field;\n\tconnection_poll[i].parser_settings.on_header_value=on_header_value;\n\tconnection_poll[i].parser_settings.on_headers_complete=on_headers_complete;\n\tconnection_poll[i].parser_settings.on_body=on_body;\n\tconnection_poll[i].parser_settings.on_message_complete=on_message_complete;\n\n\t//attach httpd connection to data (socket info) so we may retrieve it easily inside parser callbacks\n\tconnection_poll[i].parser.data=(&connection_poll[i]);\n\n\t//init parser\n\tif(in){\t\t\n\t\thttp_parser_init(&(connection_poll[i].parser),HTTP_REQUEST);\n\n\t\t//register espconn callbacks\n\t\tespconn_regist_recvcb(conn, http_process_received_cb);\n\t\tespconn_regist_reconcb(conn, http_process_reconnect_cb);\n\t\tespconn_regist_disconcb(conn, http_process_disconnect_cb);\n\t\tespconn_regist_sentcb(conn, http_process_sent_cb);\n\t}\n\telse{\t\t\n\t\thttp_parser_init(&(connection_poll[i].parser),HTTP_RESPONSE);\n\n\t\tconnection_poll[i].espConnection = &connection_poll[i].client_connection;\n\n\t\tconnection_poll[i].espConnection->reverse=&connection_poll[i]; //set reverse object \n\n\t\tconnection_poll[i].espConnection->type=ESPCONN_TCP;\n\t\tconnection_poll[i].espConnection->state=ESPCONN_NONE;\n\t\tconnection_poll[i].espConnection->proto.tcp = &connection_poll[i].client_tcp;\n\n\t\t//register espconn callbacks\n\t\tespconn_regist_recvcb(connection_poll[i].espConnection, http_process_received_cb);\n\t\tespconn_regist_reconcb(connection_poll[i].espConnection, http_process_reconnect_cb);\n\t\tespconn_regist_disconcb(connection_poll[i].espConnection, http_process_disconnect_cb);\n\t\tespconn_regist_sentcb(connection_poll[i].espConnection, http_process_sent_cb);\t\t\n\t}\n\t\n\t\n\tespconn_regist_time(conn,30,0);\n\n\treturn &connection_poll[i];\n\n}\n\nstatic void ICACHE_FLASH_ATTR http_process_init(){\n\n\tint i;\n\t//init connection pool\n\tfor (i=0; i<MAX_CONNECTIONS; i++) {\n\t\t//init with 0s\n\t\tos_memset(&connection_poll[i],0,sizeof(http_connection));\n\n\t}\n\n}\n\n"
  },
  {
    "path": "app/http/http_process.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef http_server_h\n#define http_server_h\n\n#include \"http_parser.h\"\n\n#define HTTPD_CGI_MORE 0 //when we want to lock cgi on that function\n#define HTTPD_CGI_DONE 1\n#define HTTPD_CGI_NOTFOUND 2 //not found on that cgi\n#define HTTPD_CGI_AUTHENTICATED 2 //for now\n#define HTTPD_CGI_NEXT_RULE 3 //allow other cgi to execute\n\n#define HTTPD_STATE_ON_URL 0\n#define HTTPD_STATE_ON_STATUS 1\n#define HTTPD_STATE_HEADERS_END 2\n#define HTTPD_STATE_ON_BODY 3\n#define HTTPD_STATE_BODY_END 4\n#define HTTPD_STATE_WS_DATA 5\n#define HTTPD_STATE_WS_DATA_SENT 6\n#define HTTPD_STATE_WS_CLIENT_DISCONNECT 7\n\n//client\n#define HTTP_CLIENT_CGI_MORE 0\n#define HTTP_CLIENT_CGI_DONE 1\n\n#define HTTP_CLIENT_DNS_FOUND 100\n#define HTTP_CLIENT_DNS_NOT_FOUND 101\n#define HTTP_CLIENT_CONNECT_OK 200\n#define HTTP_CLIENT_CONNECT_FAIL 201\n#define HTTP_CLIENT_REQUEST_HEADERS_SENT 202\n#define HTTP_CLIENT_REQUEST_BODY_SENT 203\n\n//ws\n#define HTTP_WS_CGI_MORE 0\n#define HTTP_WS_CGI_DONE 1\n\n#define MAX_CONNECTIONS 8\n\n#include \"http.h\"\n\nint ICACHE_FLASH_ATTR http_transmit(http_connection *c);\nint ICACHE_FLASH_ATTR http_write(http_connection *c,const char * message);\nint ICACHE_FLASH_ATTR http_nwrite(http_connection *c,const char * message,size_t size);\n\nvoid ICACHE_FLASH_ATTR http_process_free_connection(http_connection *conn);\n\n\nchar * ICACHE_FLASH_ATTR http_url_get_path(http_connection *c);\nchar * ICACHE_FLASH_ATTR http_url_get_host(http_connection *c);\nchar * ICACHE_FLASH_ATTR http_url_get_query(http_connection *c);\nchar * ICACHE_FLASH_ATTR http_url_get_query_param(http_connection *c,char* param);\n\n\nvoid ICACHE_FLASH_ATTR http_parse_url(http_connection *c);\nhttp_connection ICACHE_FLASH_ATTR * http_new_connection(uint8_t in,struct espconn *conn);\nvoid http_execute_cgi(http_connection *conn);\n\n\nvoid ICACHE_FLASH_ATTR http_set_save_header(http_connection *conn,const char* header);\nvoid ICACHE_FLASH_ATTR http_set_save_body(http_connection *conn);\nheader * ICACHE_FLASH_ATTR http_get_header(http_connection *conn,const char* header);\n\n\n\n\n#endif\n\n\n"
  },
  {
    "path": "app/http/http_server.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"c_types.h\"\n#include \"user_interface.h\"\n#include \"espconn.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"c_stdio.h\"\n\n#include \"espconn.h\"\n#include \"http_parser.h\"\n#include \"http_server.h\"\n#include \"http_helper.h\"\n#include \"http_process.h\"\n#include \"user_config.h\"\n\n#include \"cgi.h\"\n\n\n\nstatic http_server_config server_config;\n\n// Called after cgi execution to flush any data\nvoid ICACHE_FLASH_ATTR http_send_response(http_connection * conn){\n\n\tNODE_DBG(\"http_send_response\");\n\tint sent = http_transmit(conn);\n\n\t//any data sent?\n\tif(sent == 0){\n\t\t//if there was no data sent and cgi is done, we should destroy the connection\n\t\tif (conn->cgi.done==1) { \n\t\t\tNODE_DBG(\"Conn %p is done. Closing.\", conn->espConnection);\n\t\t\tespconn_disconnect(conn->espConnection);\n\t\t\thttp_process_free_connection(conn);\t\t\t\t\n\t\t\treturn; \n\t\t}\n\n\t}\t\n\n}\n\nint ICACHE_FLASH_ATTR http_server_flag_check(http_connection *c,http_server_url *url){\n\tNODE_DBG(\"http_server_flag_check\");\n\tint r=HTTPD_CGI_NEXT_RULE;\n\n\tif(url->method!=HTTP_ANY_METHOD){\n\t\tc->cgi.argument=&url->method;\n\t\tr = cgi_enforce_method(c);\n\t\tif(r==HTTPD_CGI_DONE) return r; //return now as request already failed\n\t}\n\t\n\tif(url->flags & NEED_BODY){\n\t\tr = cgi_enforce_body(c);\n\t\tif(r==HTTPD_CGI_DONE) return r; //return now as request already failed\n\t}\n\t\n\treturn r;\n}\n\n// CGI dispatcher for the http server\n//\nint ICACHE_FLASH_ATTR http_server_cgi_execute(http_connection * conn){\n\n\tNODE_DBG(\"http_execute_cgi\");\n\n\t//request is finished and we should start sending response\n\t//if not final, cgi should not expect data to be sent\n\tuint8_t final = conn->state==HTTPD_STATE_BODY_END;\n\n\tif(conn->cgi.done)\n\t\treturn 0;\n\n\t//Any CGI function already attached?\n\tif(conn->cgi.function!=NULL){ \n\n\t\tNODE_DBG(\"Executing previous cgi \");\n\n\t\tint r;\n\t\tr=conn->cgi.function(conn);\n\t\tNODE_DBG(\"Cgi return is %d\", r);\n\t\t\n\t\tif(r==HTTPD_CGI_DONE){\n\t\t\tconn->cgi.function=NULL; //mark for destruction\n\t\t\tconn->cgi.done=1;\t\t\t\t\t\t\n\t\t}\n\t\t\n\t\tif(final)\n\t\t\thttp_send_response(conn);\n\n\t\tif(r==HTTPD_CGI_MORE ||r==HTTPD_CGI_DONE){\n\t\t\treturn 0;\n\t\t}\t\t\n\n\t}\n\telse{\n\t\t//find which cgi to execute base on the url\n\n\t\tNODE_DBG(\"Finding cgi to execute \");\n\n\t\tint i=0;\n\t\twhile (server_config.urls[i]->url!=NULL && conn->url!=NULL) {\n\n\t\t\t\n\t\t\tconst char * url = server_config.urls[i]->url; \n\t\t\t//NODE_DBG(\"Checking url %s against %s\",server_config.urls[i]->url,conn->url);\n\n\t\t\tint match=0;\n\t\t\t\n\t\t\tchar *url_path = http_url_get_path(conn);\n\t\t\tNODE_DBG(\"Url path: %s\",url_path);\n\n\t\t\tif (os_strcmp(url, url_path)==0) match=1;\n\n\t\t\tif (url[os_strlen(url)-1]=='*' &&\n\t\t\t\t\tos_strncmp(url, url_path, os_strlen(url)-1)==0) match=1;\n\n\t\t\tif (match) {\n\t\t\t\tNODE_DBG(\"Url match index %d\", i);\n\n\t\t\t\t//general rules go here\t\t\t\t\n\t\t\t\tint r = http_server_flag_check(conn,server_config.urls[i]);\n\t\t\t\t\n\t\t\t\tif(r!=HTTPD_CGI_DONE){\n\t\t\t\t\t//if passed general rules\n\t\t\t\t\t//execute cgi\n\t\t\t\t\tconn->cgi.function=server_config.urls[i]->cgiFunction;\n\t\t\t\t\tconn->cgi.argument=server_config.urls[i]->cgiArgument;\n\t\t\t\t\tr=conn->cgi.function(conn);\n\t\t\t\t}\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\tNODE_DBG(\"Cgi return is %d\", r);\t\t\t\t\n\n\t\t\t\tif(r==HTTPD_CGI_DONE){ // cgi is done, nothing more to do\n\t\t\t\t\tconn->cgi.function=NULL; //mark for destruction\n\t\t\t\t\tconn->cgi.done=1;\n\t\t\t\t\thttp_send_response(conn); //force sending the response regardless of the state we are\n\t\t\t\t\treturn 0; //exit loop and return\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif(final) // if we are in final state, try to send the response for any return case\n\t\t\t\t\thttp_send_response(conn);\t\t\t\t\n\n\t\t\t\tif(r==HTTPD_CGI_NEXT_RULE){ //cgi signal that we should allow other cgi to execute on the same url\n\t\t\t\t\tconn->cgi.function=NULL;\t//clear cgi function\t\t\t\t\t\n\t\t\t\t}\n\n\t\t\t\tif(r==HTTPD_CGI_NOTFOUND){\t//the cgi doesn't recognize the request\t\t\t\t\n\t\t\t\t\tconn->cgi.function=NULL; //clear cgi function\t\t\t\t\t\n\t\t\t\t}\t\t\t\t\n\n\t\t\t\tif(r==HTTPD_CGI_MORE){ //cgi signaled ok, but there's more to do on a next round\n\t\t\t\t\treturn 0; // return so cgi function remains attached\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}\t\t\n\t\t\ti++;\n\t\t}\n\n\t\t\n\n\t}\t\n\n\tif(final){\n\t\t//if we got here, it's a 404\n\t\thttp_response_NOT_FOUND(conn);\n\t\tconn->cgi.function=NULL; //clear cgi\t\n\t\tconn->cgi.done=1; //mark cgi end\n\t\thttp_send_response(conn);\t\t\t\n\t}\n\n\treturn 0;\n\n}\n\n// called when a client connects to our server\nvoid ICACHE_FLASH_ATTR http_server_connect_callback(void *arg) {\n\n\tstruct espconn *conn=arg;\n\n\thttp_connection *c = http_new_connection(1,conn); // get a connection from the pool, signal it's an incomming connection\n\tc->cgi.execute = http_server_cgi_execute; // attach our cgi dispatcher\t\n\n\t//let's disable NAGLE alg so TCP outputs faster ( in theory )\n\tespconn_set_opt(conn, ESPCONN_NODELAY | ESPCONN_REUSEADDR );\n\n}\n\n//SERVER CONFIG FUNCTIONS ---------------------------------------------------\n\nvoid ICACHE_FLASH_ATTR http_server_init() {\t\n\t\n\tespconn_delete(&server_config.server_conn); //just to be sure we are on square 1\n\t\n\tserver_config.server_conn.type = ESPCONN_TCP;\n\tserver_config.server_conn.state = ESPCONN_NONE;\n\tserver_config.server_conn.proto.tcp = &server_config.server_tcp;\n\tserver_config.server_conn.proto.tcp->local_port = 80;\t\n\t\n\tNODE_DBG(\"Http server init, conn=%p\", &server_config.server_conn);\n\t\n}\n\n\nvoid ICACHE_FLASH_ATTR http_server_bind_port(int port){\n\n\tif(server_config.server_conn.state != ESPCONN_NONE){\n\t\tNODE_DBG(\"Can't change port after server started\");\n\t\treturn;\n\t}\n\n\tserver_config.server_conn.proto.tcp->local_port = port;\n\n}\n\n//create the url map\nhttp_server_url checkHost_url = {\"*\", cgi_check_host, &server_config,HTTP_ANY_METHOD,NO_FLAG};\nhttp_server_url cors_url = {\"*\", cgi_cors, &server_config,HTTP_ANY_METHOD,NO_FLAG};\nhttp_server_url fileSystem_url = {\"*\", cgi_file_system, NULL,HTTP_ANY_METHOD,NO_FLAG};\nhttp_server_url null_url = {NULL,NULL,NULL,HTTP_ANY_METHOD,NO_FLAG};\nvoid ICACHE_FLASH_ATTR http_server_bind_urls(http_server_url *urls){\n\n\tint i;\n\tint count=0;\n\n\t//count urls\n\twhile(urls[count].url!=NULL) count++;\n\n\n\tif(server_config.urls){\t\t\n\t\t//free alloced rewrite urls\n\t\tfor(i=0;i<server_config.rewrite_count;i++){\n\t\t\tos_free( server_config.urls[2+i] );\n\t\t}\n\n\t\tos_free(server_config.urls);\n\t}\n\n \tint array_size = server_config.rewrite_count + count + 4;\n\tserver_config.urls = (http_server_url **)os_zalloc(sizeof(http_server_url *) * (array_size) );\n\t\n\tserver_config.urls[0]=&checkHost_url;\n\tserver_config.urls[1]=&cors_url;\n\tserver_config.urls[array_size-2]=&fileSystem_url;\n\tserver_config.urls[array_size-1]=&null_url;\n\n\t\n\tfor(i=0;i<server_config.rewrite_count;i++){\n\n\t\thttp_server_url *rewrite_url = (http_server_url *)os_zalloc(sizeof(http_server_url));\n\t\trewrite_url->url=server_config.rewrites[i].match_url;\n\t\trewrite_url->cgiFunction=cgi_url_rewrite;\n\t\trewrite_url->cgiArgument=server_config.rewrites[i].rewrite_url;\n\t\trewrite_url->method=HTTP_ANY_METHOD;\n\t\trewrite_url->flags=NO_FLAG;\n\t\tserver_config.urls[2+i]=rewrite_url;\n\t}\n\t\n\tfor(i=0;i<count;i++)\n\t\tserver_config.urls[i+2+server_config.rewrite_count]=&urls[i];\n\n\t#ifdef DEVELOP_VERSION\n\tNODE_DBG(\"http server urls:\");\n\tfor(i=0;i<array_size;i++){\n\n\t\tNODE_DBG(\"\\t%d %s\",i,server_config.urls[i]->url);\n\n\t}\n\n\t#endif\n\n}\n\n//Should be called before http_server_bind_urls\nvoid ICACHE_FLASH_ATTR http_server_rewrite(url_rewrite *rewrites){\n\n\tint count=0;\n\t//count urls\n\twhile(rewrites[count].match_url!=NULL) count++;\n\n\tserver_config.rewrites=rewrites;\n\tserver_config.rewrite_count=count;\n}\n\nvoid ICACHE_FLASH_ATTR http_server_bind_domain(const char * domain){\n\t\n\tserver_config.host_domain = domain;\n}\n\nvoid ICACHE_FLASH_ATTR http_server_enable_captive_portal(){\n\t\n\tserver_config.enable_captive=1;\n\n}\nvoid ICACHE_FLASH_ATTR http_server_enable_cors(){\n\t\n\tserver_config.enable_cors=1;\n}\n\nvoid ICACHE_FLASH_ATTR http_server_start(){\n\n\tif(!server_config.urls)\n\t\thttp_server_bind_urls(NULL);\n\n\tNODE_DBG(\"Http server start, conn=%p\", &server_config.server_conn);\n\tespconn_regist_connectcb(&server_config.server_conn, http_server_connect_callback);\t\n\tespconn_accept(&server_config.server_conn);\n\n\tespconn_tcp_set_max_con_allow(&server_config.server_conn,10);\n\tNODE_DBG(\"Http server max conn = %d\", espconn_tcp_get_max_con_allow(&server_config.server_conn));\n\n\t\n}\n"
  },
  {
    "path": "app/http/http_server.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __HTTP_SERVER_H\n#define __HTTP_SERVER_H\n\n#include \"http.h\"\n\n#define ANY_HOST NULL\n#define HTTP_ANY_METHOD -1\n#define NO_FLAG 0\n\n#define NEED_POST\t1<<0\n#define NEED_GET\t1<<1\n#define NEED_BODY\t1<<2\n\n//A struct describing an url and how it should be processed\ntypedef struct {\t\n\tconst char *url;\n\thttp_callback cgiFunction;\n\tconst void *cgiArgument;\n\tenum http_method method;\n\tuint32_t flags;\n} http_server_url;\n\ntypedef struct{\n\tchar * match_url;\n\tchar * rewrite_url;\n}url_rewrite;\n\ntypedef struct {\n\n\t//Listening connection data\n\tstruct espconn server_conn;\n\tesp_tcp server_tcp;\n\n\thttp_server_url **urls;\n\n\tconst char * host_domain;\n\tint port;\n\n\tuint8_t enable_captive;\n\tuint8_t enable_cors;\n\t\n\turl_rewrite * rewrites;\t\n\tint rewrite_count;\n\n} http_server_config;\n\n\n\nvoid ICACHE_FLASH_ATTR http_server_init();\nvoid ICACHE_FLASH_ATTR http_server_bind_port(int port);\nvoid ICACHE_FLASH_ATTR http_server_bind_domain(const char * domain);\nvoid ICACHE_FLASH_ATTR http_server_bind_urls(http_server_url *urls);\nvoid ICACHE_FLASH_ATTR http_server_enable_captive_portal();\nvoid ICACHE_FLASH_ATTR http_server_enable_cors();\nvoid ICACHE_FLASH_ATTR http_server_start();\n\n#endif"
  },
  {
    "path": "app/http/http_websocket_server.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"c_types.h\"\n#include \"user_interface.h\"\n#include \"espconn.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"c_stdio.h\"\n\n#include \"espconn.h\"\n#include \"http_parser.h\"\n#include \"http_helper.h\"\n#include \"http_process.h\"\n#include \"http_websocket_server.h\"\n#include \"user_config.h\"\n\n#include \"ssl/ssl_crypto.h\"\n#include \"util/base64.h\"\n\n#include \"websocket.h\"\n\n#define WS_PORT 8088\n\nstatic http_ws_config ws_config;\n\nstatic void ICACHE_FLASH_ATTR ws_output_write_function(const char * data,size_t len,void *arg){\n\n\thttp_connection *c = (http_connection *)arg;\n\thttp_nwrite(c,data,len);\n}\n\nstatic http_callback app_callback;\nstatic http_callback data_sent_callback;\nstatic http_callback client_disconnected_callback;\nstatic http_callback client_connected_callback;\n\nstatic void http_ws_handle_message(http_connection *c,ws_frame *msg){\n\n\tif(c->cgi.function!=NULL){\n\n\t\t//put frame on argument\n\t\tc->cgi.argument=(void *)msg;\n\t\t//call cgi\n\t\tint r = c->cgi.function(c);\n\t\tint sent = http_transmit(c);\n\n\t\tif(r==HTTP_WS_CGI_DONE){\n\t\t\t//we should close the socket\n\t\t\tc->cgi.done=1;\n\n\t\t\tif(sent==0){\n\t\t\t\t//we should active close it now as no data was sent, so there will be no further callback\n\t\t\t\t//TODO send close frame instead of hard closing\n\t\t\t\tespconn_disconnect(c->espConnection);\n\t\t\t\thttp_process_free_connection(c);\t\n\t\t\t}\n\t\t}\n\n\t\t\n\t}\n\n}\n\n\nstatic const char  *ws_uuid =\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\nint ICACHE_FLASH_ATTR http_ws_handle_connect(http_connection *c) {\t\n\n\tNODE_DBG(\"http_ws_handle_connect c =%p\",c);\n\n\tif(c->state == HTTPD_STATE_ON_URL){\n\t\thttp_set_save_header(c,HTTP_ORIGIN);\t\n\t\thttp_set_save_header(c,HTTP_CONNECTION);\t\n\t\thttp_set_save_header(c,HTTP_UPGRADE);\t\t\n\t\thttp_set_save_header(c,HTTP_SEC_WEBSOCKET_KEY);\n\t\thttp_set_save_header(c,HTTP_SEC_WEBSOCKET_PROTOCOL);\n\t\thttp_set_save_header(c,HTTP_SEC_WEBSOCKET_VERSION);\n\n\t\treturn HTTP_WS_CGI_MORE;\n\t}\n\n\t//wait handshake request complete\n\tif(c->state != HTTPD_STATE_BODY_END)\n\t\treturn HTTP_WS_CGI_MORE;\n\n\n\theader * upgrade_header = http_get_header(c,HTTP_UPGRADE);\n\theader * connection_header = http_get_header(c,HTTP_CONNECTION);\n\theader * origin_header = http_get_header(c,HTTP_ORIGIN);\n\theader * key_header = http_get_header(c,HTTP_SEC_WEBSOCKET_KEY);\n\n\tif(upgrade_header==NULL) goto badrequest;\n\tif(connection_header==NULL) goto badrequest;\n\tif(origin_header==NULL) goto badrequest;\n\tif(key_header==NULL) goto badrequest;\n\n\tNODE_DBG(\"headers ok\");\n\n\tif(os_strcasecmp(upgrade_header->value,\"websocket\")!=0) goto badrequest;\n\n\t// Following (https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17)\n\t//calculate sha1 of concatenetion key+uuid\n\tuint8_t digest[20]; //sha1 is always 20 byte long\n\tSHA1_CTX ctx;\n\tSHA1_Init(&ctx);\n\tSHA1_Update(&ctx,key_header->value,os_strlen(key_header->value));\n\tSHA1_Update(&ctx,ws_uuid,os_strlen(ws_uuid));\n\tSHA1_Final(digest,&ctx);\n\t\t\n\tchar base64Digest[31]; // \n\tBase64encode(base64Digest,(const char*)digest,20);\n\n\t//accept the handshake\n\thttp_SET_HEADER(c,HTTP_UPGRADE,\"WebSocket\");\n\thttp_SET_HEADER(c,HTTP_CONNECTION,\"Upgrade\");\n\t\n\thttp_SET_HEADER(c,HTTP_WEBSOCKET_ACCEPT,base64Digest);\n\n\thttp_websocket_HANDSHAKE(c);\n\tc->handshake_ok=1;\n\n\tif(client_connected_callback!=NULL)\n\t\tclient_connected_callback(c);\n\n\treturn HTTP_WS_CGI_MORE;\n\nbadrequest:\n\thttp_response_BAD_REQUEST(c);\n\treturn HTTP_WS_CGI_DONE;\n\n}\n\n\n\nstatic int ICACHE_FLASH_ATTR http_ws_cgi_execute(http_connection * c){\n\n\tNODE_DBG(\"http_ws_cgi_execute c =%p\",c);\n\n\tif(!c->handshake_ok)\n\t{\n\t\tint r = http_ws_handle_connect(c);\n\t\tif(r==HTTP_WS_CGI_DONE)\n\t\t\tc->cgi.done=1; //mark for destruction\n\t\t\n\t\thttp_transmit(c);\n\t}\n\telse{\n\n\t\tif(c->body.data==NULL){\n\n\t\t\tif(c->state==HTTPD_STATE_WS_DATA_SENT){\n\t\t\t\tif(data_sent_callback!=NULL)\n\t\t\t\t\tdata_sent_callback(c);\t\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t}\n\t\telse if(c->state==HTTPD_STATE_WS_DATA){\n\n\t\t\tNODE_DBG(\"websocket frame size %d\",c->body.len);\n\n\t\t\tws_frame frame;\n\t\t\tws_parse_frame(&frame,c->body.data,c->body.len);\n\n\n\t\t\tswitch(frame.TYPE){\n\n\t\t\t\tcase WS_INVALID:\n\t\t\t\t\tNODE_DBG(\"\\treceived invalid frame\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase WS_PING:\n\t\t\t\t\t//send ping\n\t\t\t\t\tws_output_frame(&frame,WS_PING,\"PING\",strlen(\"PING\"));\n\t\t\t\t\tws_write_frame(&frame,ws_output_write_function,c);\n\t\t\t\t\thttp_transmit(c);\n\t\t\t\tcase WS_CLOSE:\n\t\t\t\t\t//send close back\n\t\t\t\t\tws_output_frame(&frame,WS_PING,\"\\0\\0\",2);\n\t\t\t\t\tws_write_frame(&frame,ws_output_write_function,c);\n\t\t\t\t\thttp_transmit(c);\n\t\t\t\t\t//mark as done\n\t\t\t\t\tc->cgi.done=1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase WS_TEXT:\n\t\t\t\tcase WS_BINARY:\n\t\t\t\t\thttp_ws_handle_message(c,&frame);\n\t\t\t\t\tbreak;\n\t\t\t\tcase WS_CONTINUATION:\n\t\t\t\t\tbreak; // TODO: Implement continuation logic\n\n\t\t\t}\t\t\n\n\n\t\t}\n\t\telse if(c->state == HTTPD_STATE_WS_CLIENT_DISCONNECT){\n\n\t\t\tif(client_disconnected_callback!=NULL)\n\t\t\t\tclient_disconnected_callback(c);\n\t\t}\n\n\t\treturn 1;\n\n\t}\n\n}\n\n// called when a client connects to our server\nstatic void ICACHE_FLASH_ATTR http_ws_connect_callback(void *arg) {\n\n\tstruct espconn *conn=arg;\n\n\thttp_connection *c = http_new_connection(1,conn); // get a connection from the pool, signal it's an incomming connection\n\tc->cgi.execute = http_ws_cgi_execute; \t\t  // attach our cgi dispatcher\t\n\n\t//attach app callback to cgi function\n\tc->cgi.function=app_callback;\n\n\tc->handshake_ok=0;\n\n\t//let's disable NAGLE alg so TCP outputs faster ( in theory )\n\tespconn_set_opt(conn, ESPCONN_NODELAY | ESPCONN_REUSEADDR );\n\n\t//override timeout to 240s\n\tespconn_regist_time(conn,240,0);\n\n}\n\n//PUBLIC function\n\nvoid ICACHE_FLASH_ATTR http_ws_push_text(http_connection *c,char *msg,size_t msgLen){\n\n\tws_frame frame;\n\tws_output_frame(&frame,WS_TEXT,msg,msgLen);\n\tws_write_frame(&frame,ws_output_write_function,c);\t\n\thttp_transmit(c);\n\n}\n\nvoid ICACHE_FLASH_ATTR http_ws_push_bin(http_connection *c,char *msg,size_t msgLen){\n\n\tws_frame frame;\n\tws_output_frame(&frame,WS_BINARY,msg,msgLen);\n\tws_write_frame(&frame,ws_output_write_function,c);\n\thttp_transmit(c);\n\t\n}\n\nvoid ICACHE_FLASH_ATTR http_ws_server_init(http_callback connect,http_callback disconnect,http_callback received,http_callback data_sent)\n{\t\n\n\tapp_callback = received;\n\tdata_sent_callback=data_sent;\n\tclient_disconnected_callback = disconnect;\n\tclient_connected_callback = connect;\n\n\tespconn_delete(&ws_config.server_conn); //just to be sure we are on square 1\n\t\n\tws_config.server_conn.type = ESPCONN_TCP;\n\tws_config.server_conn.state = ESPCONN_NONE;\n\tws_config.server_conn.proto.tcp = &ws_config.server_tcp;\n\tws_config.server_conn.proto.tcp->local_port = WS_PORT;\t\t\n\n\tNODE_DBG(\"Websocket server init, conn=%p\", &ws_config.server_conn);\n\n}\n\n\nvoid ICACHE_FLASH_ATTR http_ws_server_start(){\n\n\n\tNODE_DBG(\"Websocket server start, conn=%p\", &ws_config.server_conn);\n\tespconn_regist_connectcb(&ws_config.server_conn, http_ws_connect_callback);\t\n\tespconn_accept(&ws_config.server_conn);\n\n}\n"
  },
  {
    "path": "app/http/http_websocket_server.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __HTTP_WS_SERVER_H\n#define __HTTP_WS_SERVER_H\n\ntypedef struct {\n\n\t//Listening connection data\n\tstruct espconn server_conn;\n\tesp_tcp server_tcp;\n\n\tconst char * host_domain;\n\tint port;\n\n\n} http_ws_config;\n\nvoid ICACHE_FLASH_ATTR http_ws_push_bin(http_connection *c,char *msg,size_t msgLen);\nvoid ICACHE_FLASH_ATTR http_ws_push_text(http_connection *c,char *msg,size_t msgLen);\nvoid ICACHE_FLASH_ATTR http_ws_server_init();\nvoid ICACHE_FLASH_ATTR http_ws_server_start();\n\n#endif"
  },
  {
    "path": "app/http/rofs.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"osapi.h\"\n#include \"c_types.h\"\n#include \"c_stdio.h\"\n\n#include \"rofs.h\"\n#include \"rofs_data.c\"\n#include \"platform/common.h\"\n\n//Accessing the flash through the mem emulation at 0x40200000 is a bit hairy: All accesses\n//*must* be aligned 32-bit accesses. Reading a short, byte or unaligned word will result in\n//a memory exception, crashing the program.\n//\n\n//This function assumes both src and dst are 4byte aligned\n//Reading 4bytes at a time speeds up reading from flash\n\nvoid ICACHE_FLASH_ATTR memcpyAligned(char *dst,const uint8 *src, int len) {\n\t\n\tuint32_t *dst32 = (uint32_t*)dst;\n\tuint32_t *src32 = (uint32_t*)src;\n\t\n\twhile(len>0){\n\t\t\n\t\tif(len>3){\n\t\t\t*dst32=*src32;\t\n\t\t\tdst32++;\n\t\t\tsrc32++;\t\t\t\n\t\t\tlen-=4;\t\t\t\n\t\t}\n\t\telse{\t\t\t\n\t\t\tdst = (uint8_t*)dst32;\n\t\t\tuint32_t s = *src32;\n\t\t\tuint8_t *s8 = (uint8_t*)&s;\n\t\t\tint i;\n\t\t\tfor(i=0;len>0;i++,len--,dst++) \n\t\t\t\t*dst=s8[i];\n\n\t\t\tlen=0;\n\t\t}\n\n\t}\n\n}\n\nRO_FILE* f_open(const char *fileName){\n\n\tconst char *fName = fileName;\n\n\tif(*fName=='/') //skip leading /\n\t\tfName++;\n\n\tNODE_DBG(\"Trying to open file %s \",fName);\n\tNODE_DBG(\"FS Location %p \",ro_file_system);\n\tNODE_DBG(\"FS data Location %p \",rofs_data);\n\n\tint i=0;\n\twhile(i<ro_file_system.count){\n\n\t\tconst RO_FILE_ENTRY *entry = &ro_file_system.files[i];\n\t\t\n\t\tNODE_DBG(\"Checking %s\",entry->name);\n\n\t\tif(os_strcmp(fName,entry->name)==0){\n\n\t\t\tRO_FILE *f = (RO_FILE*)os_malloc(sizeof(RO_FILE));\n\t\t\tf->file = entry;\n\t\t\tf->readPos=0;\n\n\t\t\treturn f;\n\t\t}\n\t\ti++;\n\n\t}\n\n\treturn NULL;\n}\n\n\n\nint f_read(RO_FILE *f,char * buff,int len){\n\n\tif(f==NULL)\n\t\treturn 0;\n\n\tint bytesToRead = len;\n\tint remLen = f->file->size - f->readPos;\n\tif(remLen < len)\n\t\tbytesToRead=remLen;\n\n\tNODE_DBG(\"Reading %d bytes from %s\",bytesToRead,f->file->name);\n\tmemcpyAligned(buff,rofs_data+f->file->offset+f->readPos,bytesToRead);\t\n\t//platform_flash_read(buff,(uint32_t)(rofs_data+f->file->offset+f->readPos),bytesToRead);\n\tf->readPos+=bytesToRead;\n\t\n\tf->eof= (f->readPos == f->file->size);\t\n\n\treturn bytesToRead;\n\n}\n\nvoid f_close(RO_FILE *file){\n\n\tif(file!=NULL)\n\t\tos_free(file);\n\n}"
  },
  {
    "path": "app/http/rofs.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __ROFS_H\n#define __ROFS_H\n\n#include \"c_stdlib.h\"\n#include \"c_stdint.h\"\n#include \"c_stddef.h\"\n#include \"user_interface.h\"\n#include \"user_config.h\"\n\ntypedef struct {\n\n\tsize_t size;\n\tuint8_t gzip;\n\tconst char *name;\t\n\tuint32_t offset;\t\n\n} RO_FILE_ENTRY;\n\ntypedef struct {\n\n\tsize_t count;\n\tRO_FILE_ENTRY files[];\n\n} RO_FS;\n\n\ntypedef struct {\n\n\tconst RO_FILE_ENTRY *file;\n\tuint32_t readPos;\n\tuint8_t eof;\n\n} RO_FILE;\n\nRO_FILE* ICACHE_FLASH_ATTR f_open(const char *fileName);\nint ICACHE_FLASH_ATTR f_read(RO_FILE *file,char * buff,int len);\nvoid ICACHE_FLASH_ATTR f_close(RO_FILE *file);\n\n#endif"
  },
  {
    "path": "app/http/rofs_data.c",
    "content": "//Generated by MKFS tool\r\n//\r\n#include \"rofs.h\"\r\n#include \"c_types.h\"\r\n#define ROFS_FILE_COUNT 7\r\nconst RO_FS ro_file_system = {\r\n\t.count=7,\r\n\t.files={\r\n\t\t{\r\n\t\t.size=1566,\r\n\t\t.name = \"index.html\",\r\n\t\t.gzip=1,\r\n\t\t.offset=0\r\n\t\t},\r\n\t\t{\r\n\t\t.size=1755,\r\n\t\t.name = \"speed_test.html\",\r\n\t\t.gzip=1,\r\n\t\t.offset=1568\r\n\t\t},\r\n\t\t{\r\n\t\t.size=19715,\r\n\t\t.name = \"cat.jpg\",\r\n\t\t.gzip=1,\r\n\t\t.offset=3324\r\n\t\t},\r\n\t\t{\r\n\t\t.size=15791,\r\n\t\t.name = \"bootstrap.css\",\r\n\t\t.gzip=1,\r\n\t\t.offset=23040\r\n\t\t},\r\n\t\t{\r\n\t\t.size=2323,\r\n\t\t.name = \"index.js\",\r\n\t\t.gzip=1,\r\n\t\t.offset=38832\r\n\t\t},\r\n\t\t{\r\n\t\t.size=22718,\r\n\t\t.name = \"lib.js\",\r\n\t\t.gzip=1,\r\n\t\t.offset=41156\r\n\t\t},\r\n\t\t{\r\n\t\t.size=528,\r\n\t\t.name = \"cats.html\",\r\n\t\t.gzip=1,\r\n\t\t.offset=63876\r\n\t\t}\r\n\t}\r\n};\r\nconst ICACHE_STORE_ATTR ICACHE_RODATA_ATTR uint8_t rofs_data[]={0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0xbd, 0x58, 0x5b, 0x6f, 0xdb, 0x36, 0x14, 0x7e, 0x76, 0x81, 0xfc, 0x7, 0x96, 0x45, 0x81, 0x3d, 0x8c, 0x91, 0x93, 0xb4, 0xc0, 0xe0, 0xca, 0x1a, 0x86, 0x74, 0xc5, 0xfa, 0xd2, 0x15, 0x73, 0x80, 0x62, 0x8f, 0xb4, 0x44, 0x5b, 0x6c, 0x25, 0x51, 0xa3, 0x28, 0x27, 0xc6, 0xb0, 0xff, 0xbe, 0xc3, 0x8b, 0x68, 0xea, 0xe2, 0xd4, 0x49, 0x83, 0x4, 0x6d, 0xc2, 0xcb, 0x39, 0xe7, 0x3b, 0x3c, 0x3c, 0x37, 0xea, 0xec, 0x45, 0x9c, 0xab, 0xb2, 0x48, 0xce, 0x5e, 0x9c, 0xc1, 0x88, 0xd1, 0xc, 0x46, 0x8, 0xc5, 0x8a, 0xab, 0x82, 0x25, 0xab, 0x92, 0x4a, 0x85, 0xfe, 0x62, 0x5, 0xdd, 0xc7, 0x91, 0x5d, 0x32, 0xbb, 0x25, 0x53, 0x14, 0xe5, 0x4a, 0xd5, 0x84, 0xfd, 0xd3, 0xf2, 0xdd, 0x12, 0x5f, 0x8b, 0x4a, 0xb1, 0x4a, 0x91, 0x9b, 0x7d, 0xcd, 0x30, 0x4a, 0xed, 0x6c, 0x89, 0x15, 0xbb, 0x53, 0x91, 0x16, 0xff, 0xe, 0xa5, 0x39, 0x95, 0xd, 0x53, 0xcb, 0x56, 0x6d, 0xc8, 0x2f, 0x38, 0x41, 0x7, 0x39, 0x15, 0x2d, 0xd9, 0x12, 0xef, 0x38, 0xbb, 0xad, 0x85, 0x54, 0x1, 0xf7, 0x2d, 0xcf, 0x54, 0xbe, 0xcc, 0xd8, 0x8e, 0xa7, 0x8c, 0x98, 0xc9, 0xcf, 0x88, 0x57, 0x5c, 0x71, 0x5a, 0x90, 0x26, 0xa5, 0x5, 0x5b, 0x5e, 0x60, 0xab, 0x4f, 0xc1, 0xab, 0x6f, 0x48, 0xb2, 0x62, 0x89, 0x1b, 0xb5, 0x2f, 0x58, 0x93, 0x33, 0x6, 0x82, 0x72, 0xc9, 0x36, 0x4b, 0xbc, 0x16, 0x42, 0x35, 0x4a, 0xd2, 0xfa, 0x3c, 0x6d, 0x1a, 0x47, 0x6f, 0xa8, 0x90, 0x2, 0x65, 0x9d, 0x8e, 0x7e, 0x6b, 0xa6, 0xe4, 0x22, 0x17, 0x3b, 0x26, 0xff, 0x35, 0xb3, 0x59, 0xda, 0xca, 0x46, 0xc8, 0x45, 0x2d, 0x38, 0x28, 0x25, 0xdf, 0x99, 0xc5, 0xff, 0x8c, 0x8c, 0xc8, 0x8, 0xb1, 0xf2, 0xa2, 0x83, 0xe1, 0xd6, 0x22, 0xdb, 0x5b, 0x49, 0x71, 0x45, 0x77, 0x28, 0x2d, 0x68, 0xd3, 0x2c, 0x31, 0xc, 0xd7, 0x54, 0x12, 0x5e, 0x81, 0xe4, 0x86, 0x21, 0x37, 0xcd, 0xd8, 0x86, 0xb6, 0x85, 0xd2, 0xc8, 0x33, 0x60, 0xcd, 0xb8, 0xa7, 0xd7, 0x36, 0xa0, 0xbc, 0x62, 0x92, 0x6c, 0x8a, 0x96, 0x67, 0x8e, 0xa2, 0x4f, 0xe3, 0x84, 0x68, 0x68, 0x26, 0x71, 0x62, 0xf6, 0x91, 0xa3, 0x3, 0x4a, 0x3a, 0xa0, 0x5b, 0x4b, 0x5a, 0x65, 0x9d, 0x51, 0x5e, 0xe1, 0x24, 0x8e, 0xa8, 0x97, 0x1a, 0x81, 0xd8, 0x29, 0x88, 0x54, 0x14, 0x5, 0xad, 0xf, 0xa, 0x77, 0x73, 0x8c, 0x78, 0x6, 0x96, 0x6d, 0x8, 0xbb, 0xa3, 0x65, 0x5d, 0x30, 0x32, 0xd8, 0x27, 0xee, 0x62, 0xc6, 0x3f, 0x71, 0x5b, 0x4, 0x7a, 0x75, 0x72, 0xe1, 0xcf, 0x31, 0x6, 0x7d, 0xb9, 0x1d, 0x7, 0x4d, 0x15, 0xdf, 0x31, 0x50, 0x9d, 0xba, 0x63, 0x44, 0x38, 0x1, 0xcf, 0xdb, 0xf0, 0xad, 0x3e, 0x4c, 0x1c, 0x15, 0xfc, 0x1e, 0x21, 0x1, 0x57, 0x53, 0x33, 0x96, 0x11, 0xc5, 0x1a, 0x30, 0xfd, 0x4a, 0x8f, 0xd1, 0xd, 0x8c, 0x4f, 0x90, 0x81, 0x2, 0x21, 0x29, 0x55, 0xe0, 0x33, 0xd7, 0xf0, 0xdb, 0x33, 0xa2, 0xa3, 0x3f, 0x47, 0x8c, 0x11, 0xb5, 0x45, 0x72, 0x22, 0xf1, 0x61, 0x31, 0xb8, 0x2d, 0x3f, 0x8c, 0x23, 0x30, 0xa1, 0x1e, 0xe8, 0xf1, 0x94, 0x1f, 0x19, 0xf, 0xd2, 0xbb, 0xb3, 0x38, 0xbf, 0xe8, 0xc7, 0x35, 0xcc, 0xc7, 0x88, 0x86, 0x52, 0xb, 0xd2, 0x17, 0x5d, 0x31, 0x75, 0x2b, 0xe4, 0x37, 0xd2, 0x28, 0xaa, 0xda, 0xc6, 0x3b, 0xe3, 0xd0, 0x5b, 0x6a, 0xba, 0x65, 0xde, 0x1d, 0xb5, 0x0, 0xd, 0x76, 0x95, 0xac, 0xc, 0x17, 0xe0, 0x5c, 0xd9, 0xc5, 0x4e, 0x69, 0x27, 0x61, 0x36, 0xb, 0x9d, 0xa2, 0xe0, 0x8d, 0x22, 0x5b, 0x29, 0xda, 0xda, 0xfa, 0x98, 0x85, 0x24, 0x7a, 0xb9, 0x93, 0xd9, 0x73, 0x89, 0x3, 0x3d, 0xe1, 0x8a, 0x95, 0x7, 0x1a, 0x1d, 0xe5, 0x35, 0xad, 0x3a, 0xba, 0x35, 0xcd, 0xb6, 0xac, 0x27, 0xb2, 0x3b, 0xc, 0x4, 0x32, 0xd0, 0x5, 0x7c, 0x56, 0x5f, 0x8f, 0x65, 0x3d, 0xe2, 0x29, 0x81, 0x1b, 0x1d, 0xd0, 0x63, 0xd8, 0xd5, 0xc7, 0xf7, 0x4f, 0xc, 0x1a, 0xa2, 0xf2, 0x7a, 0x2, 0xf3, 0xe3, 0xe7, 0x49, 0xc4, 0xa7, 0x82, 0xd4, 0x29, 0x13, 0x7c, 0x67, 0xa, 0xd8, 0x6d, 0xfd, 0x3a, 0xc6, 0x37, 0x41, 0x61, 0x47, 0xb5, 0x17, 0xde, 0x40, 0x6a, 0x29, 0x6b, 0x51, 0x41, 0x5d, 0xc0, 0xa3, 0x88, 0x99, 0x8d, 0xdd, 0x77, 0xe6, 0xe3, 0xf4, 0x15, 0xf6, 0x42, 0x54, 0x85, 0xe0, 0x3f, 0xa8, 0xb5, 0x11, 0x2e, 0x81, 0xc1, 0x2c, 0xe3, 0xd, 0x4, 0x49, 0xc5, 0x52, 0x28, 0x18, 0x26, 0xa3, 0x2f, 0x31, 0x2c, 0xd5, 0x10, 0x19, 0x8b, 0xa, 0xf0, 0x70, 0xf2, 0xde, 0x13, 0xd8, 0x8c, 0xe9, 0x21, 0x40, 0xd3, 0x3a, 0x19, 0x86, 0x65, 0x17, 0x3d, 0xc1, 0xfa, 0x28, 0x8a, 0x52, 0x5a, 0x85, 0xd9, 0x6e, 0x76, 0x42, 0xc, 0xfd, 0xb6, 0xa3, 0xbc, 0xa0, 0x6b, 0x28, 0x5a, 0x4e, 0xca, 0x44, 0x3c, 0xd, 0x25, 0x9a, 0x9b, 0x0, 0x2c, 0x52, 0x4b, 0xb1, 0x95, 0xac, 0xab, 0x70, 0xa1, 0x91, 0x40, 0xc4, 0x17, 0xca, 0x15, 0xba, 0xcd, 0x39, 0x88, 0xbe, 0x65, 0x48, 0xd3, 0xa3, 0x8d, 0x90, 0xe8, 0x96, 0x6f, 0xb8, 0xc7, 0x3a, 0x3f, 0x3f, 0x77, 0x70, 0xa3, 0xc, 0x16, 0xaa, 0xee, 0x60, 0x50, 0x37, 0x80, 0x10, 0x93, 0xbc, 0x86, 0xec, 0xea, 0xf2, 0x36, 0x42, 0xb6, 0xa2, 0xe3, 0xb7, 0xf3, 0xd7, 0x7, 0x3f, 0x9a, 0x4d, 0xc9, 0x20, 0x50, 0x15, 0xfc, 0x7d, 0x18, 0xae, 0x5, 0xba, 0x98, 0x6b, 0x36, 0x9f, 0xf2, 0xfc, 0xc9, 0x7b, 0xc9, 0x71, 0x98, 0x5d, 0xee, 0x49, 0xac, 0x7d, 0x23, 0x1, 0xaa, 0x2e, 0xc5, 0xd3, 0x3e, 0xf0, 0x1d, 0x8f, 0x9b, 0x4d, 0x89, 0x22, 0xac, 0xac, 0xd5, 0x7e, 0x64, 0x73, 0x63, 0xf4, 0x4f, 0xa2, 0xb3, 0x2d, 0x18, 0xbb, 0xad, 0x32, 0xb4, 0xf8, 0x69, 0xc2, 0xc0, 0x13, 0x37, 0x6b, 0x97, 0x95, 0xf1, 0x4, 0x67, 0x32, 0x3b, 0x31, 0xbf, 0xbd, 0xc1, 0xed, 0xcc, 0xf4, 0x31, 0x78, 0xa4, 0x97, 0xd9, 0xc, 0x92, 0xa9, 0x72, 0xcd, 0x8b, 0xf, 0x6b, 0x25, 0x3b, 0xd9, 0x4d, 0x9b, 0xa6, 0xce, 0x71, 0xba, 0x5d, 0xc3, 0x90, 0x7c, 0xb2, 0xda, 0x43, 0x53, 0x98, 0xf7, 0xf7, 0x5e, 0x12, 0x2, 0xfb, 0x5e, 0x37, 0xe8, 0xad, 0x48, 0xca, 0x74, 0xb0, 0x43, 0xa9, 0xcc, 0x29, 0x84, 0x51, 0x61, 0x78, 0x8, 0x19, 0x8a, 0x9c, 0x64, 0xf9, 0xbd, 0x4a, 0xe5, 0xbe, 0x56, 0x5c, 0x54, 0x63, 0xa4, 0x23, 0x2c, 0x2b, 0xbe, 0xad, 0xa8, 0x5, 0x99, 0x1d, 0xa8, 0x83, 0xd3, 0x45, 0x4a, 0x1e, 0xce, 0x1e, 0xf5, 0xf, 0x1f, 0x2b, 0xd3, 0xbe, 0x75, 0x8c, 0x1, 0x99, 0x6b, 0xeb, 0xac, 0xd7, 0x19, 0xb, 0x26, 0x6e, 0xfb, 0x59, 0xb2, 0x94, 0xcd, 0x19, 0x2b, 0x1d, 0x9d, 0x74, 0xb, 0x5, 0xfd, 0xfe, 0x54, 0x14, 0x76, 0x9, 0xc3, 0x79, 0x40, 0x65, 0xbc, 0xd6, 0xf9, 0x3b, 0x34, 0x4, 0x5b, 0x5e, 0x91, 0xb5, 0x50, 0x4a, 0x94, 0x8b, 0xab, 0x79, 0x7d, 0xe7, 0x2e, 0xfd, 0x3b, 0xc9, 0x9, 0xdc, 0xf9, 0x32, 0xf9, 0x5b, 0xb4, 0x12, 0x35, 0xac, 0x82, 0x4e, 0x19, 0xdc, 0xf8, 0xb2, 0x9f, 0x96, 0x3a, 0x19, 0x76, 0x88, 0xa0, 0xda, 0xc3, 0x29, 0x76, 0xb4, 0xb1, 0x7e, 0x69, 0x98, 0x88, 0x7e, 0x1c, 0xe8, 0x86, 0x9d, 0xf1, 0x6d, 0xe, 0x8d, 0xff, 0xe5, 0xdb, 0xb9, 0xe, 0x74, 0x4b, 0x37, 0x29, 0xad, 0xbb, 0xa, 0x53, 0x56, 0x6e, 0x20, 0xd2, 0x98, 0x84, 0x92, 0x23, 0xd9, 0x2, 0xb9, 0x52, 0x63, 0x6b, 0x93, 0x86, 0x80, 0xa2, 0x55, 0x93, 0x8c, 0x2a, 0x8a, 0x93, 0x39, 0xba, 0x76, 0xdb, 0x33, 0xc7, 0xbf, 0x96, 0x91, 0x1f, 0x9b, 0x8d, 0x3f, 0xda, 0x92, 0x67, 0x5c, 0xed, 0x27, 0x4, 0xe5, 0x6d, 0xe9, 0xe5, 0xbc, 0xe, 0x2b, 0x5a, 0x98, 0x92, 0xb4, 0x81, 0xa7, 0x52, 0xb2, 0xcf, 0x10, 0x52, 0x37, 0x5d, 0xb6, 0xf7, 0x7c, 0x12, 0xdb, 0xeb, 0xce, 0x15, 0xed, 0xf5, 0x5, 0x48, 0xd7, 0xce, 0x5d, 0xe, 0xcb, 0x82, 0x9e, 0x1c, 0x77, 0x34, 0xf7, 0x8, 0xb1, 0xec, 0x64, 0xdd, 0x82, 0x12, 0x15, 0x46, 0xfa, 0xa0, 0xc4, 0x2c, 0x2d, 0xf1, 0x1c, 0x7, 0x9a, 0x5b, 0x2, 0x2, 0x17, 0x64, 0xda, 0x47, 0xf4, 0x6a, 0x8e, 0xfe, 0xfc, 0xf0, 0xc1, 0x3d, 0x26, 0x7e, 0x10, 0xe8, 0x62, 0x2, 0xe8, 0xc2, 0x3, 0x5d, 0x74, 0x40, 0x43, 0x2b, 0x7, 0x3d, 0x6b, 0x70, 0x68, 0xf3, 0x6f, 0xd0, 0xe, 0x97, 0x22, 0xa3, 0x85, 0x5, 0x71, 0x35, 0x9d, 0xb8, 0xa5, 0xf1, 0x13, 0xcc, 0x6c, 0x40, 0x7b, 0x40, 0xb, 0xb1, 0xc5, 0x56, 0xe4, 0xb0, 0xe2, 0x59, 0x12, 0xf7, 0x5e, 0x45, 0x5d, 0x1b, 0x71, 0x68, 0x8f, 0xc7, 0xb4, 0xc1, 0x5, 0x6, 0x5a, 0x7b, 0x27, 0xc9, 0xdf, 0xf4, 0xc9, 0xcd, 0x93, 0xdb, 0xea, 0xeb, 0xb1, 0x8c, 0xd6, 0x76, 0x3, 0x62, 0x24, 0x7f, 0x13, 0xc0, 0x85, 0xcf, 0xb8, 0x29, 0x74, 0x9d, 0xc4, 0x8e, 0x76, 0xef, 0x50, 0xf5, 0xcb, 0xb0, 0xf3, 0xee, 0x3, 0xd6, 0x40, 0x3, 0x19, 0x3f, 0x73, 0xbe, 0xa7, 0x5b, 0x44, 0xba, 0x66, 0x45, 0xf8, 0xce, 0x90, 0xa2, 0x20, 0x66, 0x11, 0xeb, 0xe, 0xe2, 0x98, 0x0, 0x48, 0x6c, 0x75, 0xb, 0x46, 0xfa, 0xec, 0xe6, 0xd0, 0xf8, 0x69, 0x1e, 0x2f, 0xd6, 0x6c, 0xf7, 0x74, 0x72, 0xb2, 0xef, 0xd3, 0xca, 0x9, 0xd, 0x5e, 0xf4, 0x18, 0xed, 0x68, 0xd1, 0xc2, 0x4, 0x23, 0xa8, 0xe3, 0x29, 0xcb, 0x45, 0x1, 0x86, 0x5f, 0xe2, 0x2f, 0x12, 0xba, 0x58, 0x1b, 0x2f, 0xa6, 0xc5, 0x19, 0x9c, 0x6b, 0x98, 0xb4, 0xc6, 0x90, 0x95, 0x18, 0xda, 0x2, 0x2a, 0x40, 0x72, 0x93, 0x73, 0x48, 0x68, 0xd, 0x82, 0x54, 0x21, 0x6a, 0x56, 0x75, 0xd5, 0xdd, 0xa6, 0xe5, 0x43, 0xa7, 0x72, 0xfa, 0x55, 0x6d, 0x84, 0x50, 0x3, 0x47, 0x89, 0x6d, 0x44, 0xb8, 0x43, 0x76, 0xf1, 0x33, 0x1d, 0x64, 0x2e, 0xae, 0xa0, 0x8b, 0x29, 0xf9, 0xc0, 0xf1, 0xfb, 0xc7, 0x71, 0x51, 0x96, 0x16, 0x2, 0x5e, 0xf5, 0xc9, 0xb5, 0xfe, 0x13, 0x47, 0x76, 0xf1, 0xc1, 0xd8, 0xb5, 0xe4, 0x90, 0xca, 0xf6, 0xf7, 0xc1, 0x74, 0x21, 0x72, 0xdd, 0x75, 0xd4, 0x43, 0xa8, 0xfe, 0xa7, 0x88, 0x43, 0x34, 0x9f, 0x14, 0x7a, 0xbc, 0xda, 0x1e, 0x6d, 0xe0, 0x4e, 0x8, 0xca, 0x7, 0x84, 0x64, 0x77, 0x0, 0x40, 0xb4, 0xcd, 0xf1, 0x93, 0x85, 0xe1, 0x63, 0xba, 0xe8, 0x1f, 0x69, 0xa2, 0xed, 0xd0, 0x54, 0xae, 0x87, 0xfa, 0xe6, 0xd8, 0x5e, 0x8f, 0xbb, 0xbd, 0xae, 0xcb, 0x7c, 0xa6, 0xab, 0x5b, 0x59, 0xb8, 0x97, 0x8f, 0xbc, 0xb5, 0x43, 0x17, 0x8f, 0xba, 0x37, 0xd8, 0xa3, 0x63, 0xfa, 0xd9, 0x43, 0xfa, 0x21, 0x57, 0x16, 0x7c, 0x5c, 0xf2, 0xab, 0x71, 0x93, 0x82, 0x33, 0xc2, 0x95, 0xc9, 0x54, 0x7f, 0x1a, 0x58, 0x9f, 0x7f, 0x6d, 0xc2, 0xac, 0x1b, 0x7d, 0xa5, 0xd0, 0xb1, 0x19, 0x12, 0xf3, 0xe8, 0x37, 0xa3, 0x64, 0xc8, 0xc7, 0xab, 0x8c, 0xdd, 0x9d, 0xc8, 0x69, 0x3f, 0xaf, 0x76, 0x1f, 0x55, 0x63, 0xf3, 0x31, 0x39, 0xf9, 0x1f, 0x62, 0xa4, 0x88, 0x41, 0xb4, 0x16, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0xb5, 0x58, 0xeb, 0x6f, 0xdb, 0x36, 0x10, 0xff, 0x6c, 0xff, 0x15, 0xac, 0x52, 0xc0, 0x12, 0x62, 0xc9, 0x8f, 0xb4, 0x41, 0x90, 0x58, 0x6, 0xd6, 0x74, 0x8f, 0x2, 0x3, 0x56, 0x34, 0x1, 0xfa, 0x21, 0x8, 0x6, 0x5a, 0xa2, 0x6d, 0xb6, 0xb4, 0xa4, 0x89, 0x94, 0x1d, 0x2f, 0xc8, 0xff, 0xbe, 0x3b, 0x3e, 0x64, 0xc9, 0x71, 0xb2, 0x6c, 0xd9, 0xc, 0xc4, 0xa6, 0x8e, 0x77, 0xbf, 0x3b, 0xde, 0x93, 0xca, 0x64, 0xa9, 0x56, 0x62, 0xda, 0xed, 0x4e, 0x96, 0x8c, 0xa6, 0xd3, 0x2e, 0x21, 0x13, 0xc5, 0x95, 0x60, 0xd3, 0xab, 0x15, 0x2d, 0x15, 0xf9, 0xc2, 0x4, 0xdd, 0x4e, 0x6, 0x86, 0x84, 0x9b, 0x2b, 0xa6, 0x28, 0x59, 0x2a, 0x55, 0x84, 0xec, 0x8f, 0x8a, 0xaf, 0x63, 0xef, 0x32, 0xcf, 0x14, 0xcb, 0x54, 0x78, 0xbd, 0x2d, 0x98, 0x47, 0x12, 0xf3, 0x14, 0x7b, 0x8a, 0xdd, 0xa9, 0x1, 0x42, 0x5f, 0x90, 0x64, 0x49, 0x4b, 0xc9, 0x54, 0x5c, 0xa9, 0x79, 0x78, 0xe6, 0x4d, 0x49, 0xd, 0x93, 0xd1, 0x15, 0x8b, 0xbd, 0x35, 0x67, 0x9b, 0x22, 0x2f, 0x55, 0x43, 0x78, 0xc3, 0x53, 0xb5, 0x8c, 0x53, 0xb6, 0xe6, 0x9, 0xb, 0xf5, 0x43, 0x9f, 0xf0, 0x8c, 0x2b, 0x4e, 0x45, 0x28, 0x13, 0x2a, 0x58, 0x3c, 0xf2, 0xb4, 0x35, 0x82, 0x67, 0xdf, 0x49, 0xc9, 0x44, 0xec, 0x49, 0xb5, 0x15, 0x4c, 0x2e, 0x19, 0x3, 0x9c, 0x65, 0xc9, 0xe6, 0xb1, 0x37, 0xcb, 0x73, 0x25, 0x55, 0x49, 0x8b, 0x28, 0x91, 0xd2, 0xaa, 0x1d, 0xd4, 0x87, 0x9c, 0xe5, 0xe9, 0x16, 0x17, 0x9d, 0x49, 0x46, 0xd7, 0x24, 0x11, 0x54, 0xca, 0xd8, 0x83, 0xe5, 0x8c, 0x96, 0x21, 0xcf, 0xd6, 0xc, 0x2c, 0x26, 0xf6, 0x31, 0x65, 0x73, 0x5a, 0x9, 0x5, 0x1a, 0x3b, 0x20, 0x98, 0xf2, 0x9a, 0x1d, 0xed, 0xa5, 0x3c, 0x63, 0x65, 0x38, 0x17, 0x15, 0x4f, 0xd, 0x43, 0x9b, 0xc5, 0x42, 0xa0, 0x5a, 0x56, 0x7a, 0x53, 0xbd, 0x4f, 0xc, 0x1b, 0x30, 0xd2, 0x3d, 0xb6, 0x59, 0x49, 0xb3, 0xd4, 0xd9, 0x7f, 0xe4, 0x4d, 0x27, 0x3, 0xea, 0x30, 0x7, 0x0, 0x7a, 0x0, 0x3f, 0xc9, 0x85, 0xa0, 0xc5, 0xce, 0x56, 0xf7, 0xec, 0x11, 0x9e, 0x82, 0xb, 0x64, 0xc8, 0xee, 0xe8, 0xaa, 0x10, 0x2c, 0xdc, 0xdb, 0xf, 0x8d, 0x3, 0x1f, 0x7f, 0x26, 0x95, 0x68, 0x18, 0xe5, 0x60, 0xe1, 0xe7, 0x9, 0x7e, 0x8c, 0x1, 0x99, 0xc2, 0x49, 0x8c, 0xd1, 0x3, 0x6f, 0xa, 0x9, 0x31, 0xe7, 0xb, 0x34, 0x7d, 0x32, 0x10, 0xfc, 0x19, 0x29, 0xab, 0x86, 0x26, 0x8a, 0xaf, 0x99, 0xd7, 0xc0, 0x90, 0x5, 0x63, 0x69, 0xa8, 0x98, 0x4, 0x9f, 0x5f, 0xe1, 0x9a, 0x5c, 0xc3, 0xfa, 0x5, 0x88, 0xd, 0x8c, 0x84, 0x2a, 0x8, 0xfa, 0x25, 0x7c, 0xd7, 0x72, 0x7, 0xc5, 0xe, 0x3b, 0x61, 0x50, 0x89, 0xe9, 0xcb, 0x78, 0xbb, 0x3b, 0x19, 0x17, 0x21, 0xb7, 0x9a, 0xc, 0xc0, 0x6d, 0xf0, 0xb, 0xab, 0x43, 0x49, 0x83, 0xe9, 0x2, 0x7b, 0x9d, 0xc9, 0x72, 0xd4, 0x2e, 0x36, 0x78, 0x46, 0x72, 0x43, 0xa6, 0xa0, 0xb, 0x56, 0xe7, 0x10, 0xec, 0xa1, 0xd0, 0x49, 0xcb, 0x35, 0xf0, 0x88, 0x32, 0x56, 0x33, 0x6c, 0x8f, 0x31, 0x1, 0x7a, 0x52, 0x51, 0x55, 0xc9, 0x1e, 0xc6, 0x24, 0x63, 0xe0, 0xe7, 0x6c, 0x11, 0x45, 0x11, 0x70, 0x8f, 0x77, 0x4e, 0x6c, 0xea, 0x29, 0xf3, 0x8d, 0x4b, 0xe2, 0x3, 0x89, 0x16, 0x8a, 0x85, 0x4e, 0x9b, 0x7a, 0xbf, 0x65, 0xe3, 0x3c, 0x2f, 0x57, 0xe1, 0xa2, 0xcc, 0xab, 0xa2, 0xc9, 0xd2, 0x8c, 0xf, 0x9d, 0x31, 0xd1, 0xf4, 0x42, 0x89, 0x90, 0x48, 0xf4, 0xa6, 0x1f, 0xb6, 0x10, 0x6d, 0x32, 0x20, 0x5, 0x4d, 0xbe, 0x33, 0x38, 0x8e, 0x26, 0x1f, 0x86, 0x69, 0xa8, 0xe4, 0x59, 0x51, 0x29, 0xab, 0xd3, 0xe4, 0x3b, 0xc0, 0x40, 0x8a, 0x57, 0x19, 0x24, 0xce, 0x81, 0x58, 0x81, 0xdf, 0xb0, 0xf8, 0xf4, 0x47, 0x57, 0x9f, 0x2b, 0x34, 0x7, 0x28, 0xb8, 0xb4, 0x78, 0x21, 0x57, 0x6c, 0x45, 0x6c, 0x6a, 0x92, 0x94, 0x2a, 0x1a, 0x96, 0x54, 0x41, 0xb7, 0x3a, 0x19, 0x7b, 0xd3, 0x93, 0xb1, 0x29, 0xcc, 0x17, 0x3, 0x79, 0xa4, 0x9, 0x71, 0xfa, 0xce, 0x9b, 0x9e, 0xbe, 0x7b, 0x15, 0xc4, 0x68, 0xc, 0x8d, 0x14, 0xbe, 0x5e, 0x5, 0x32, 0x7e, 0x7f, 0xea, 0x4d, 0xe1, 0xeb, 0x55, 0x20, 0xef, 0x47, 0xe0, 0x10, 0xf8, 0x7a, 0xdd, 0x71, 0x86, 0x63, 0xf0, 0x9, 0x7e, 0xef, 0x60, 0xda, 0x3d, 0xef, 0x71, 0x95, 0xed, 0x95, 0x61, 0x67, 0x9f, 0x3, 0x10, 0xe, 0xe5, 0xef, 0xd0, 0x23, 0x66, 0x13, 0xb6, 0x13, 0x9a, 0xad, 0xa9, 0xd4, 0x99, 0x63, 0x5a, 0xe, 0x4e, 0x2a, 0x9c, 0x1f, 0x8c, 0x2f, 0x96, 0x30, 0x86, 0x4e, 0x86, 0x43, 0xec, 0xc1, 0x86, 0xcd, 0x42, 0x3a, 0x74, 0xbb, 0xd2, 0x15, 0xfc, 0xa8, 0x86, 0x88, 0x9e, 0x46, 0xb1, 0x7, 0x55, 0xbd, 0xe0, 0x59, 0x38, 0xcb, 0x95, 0xca, 0x57, 0xe7, 0x27, 0xc3, 0xe2, 0x4e, 0x97, 0x2f, 0x14, 0xce, 0x63, 0x7, 0xcd, 0x54, 0x46, 0xe0, 0x2f, 0x94, 0x55, 0x92, 0x30, 0x18, 0x58, 0xc4, 0xd8, 0xa5, 0xc0, 0xa2, 0x50, 0xaa, 0xbc, 0x8, 0x67, 0x15, 0xa0, 0x64, 0xd0, 0x11, 0xaf, 0x7f, 0xf8, 0x72, 0x6d, 0xfd, 0xd4, 0xb0, 0xa7, 0xdb, 0x75, 0xe5, 0xf, 0xb, 0x99, 0x94, 0xbc, 0x50, 0x44, 0x96, 0x9, 0x7a, 0x7e, 0x16, 0x7d, 0x3, 0x3c, 0x5, 0x3, 0xda, 0xce, 0xe5, 0x6f, 0x14, 0xe, 0xa4, 0x59, 0xf0, 0x7c, 0x66, 0x35, 0xed, 0x34, 0x4, 0x9f, 0xe0, 0x35, 0xd, 0xeb, 0xad, 0x3f, 0xaf, 0x32, 0xa8, 0x8c, 0x3c, 0xf3, 0x83, 0xfb, 0x2e, 0xba, 0x65, 0x4d, 0x4b, 0xb2, 0x91, 0xbf, 0x27, 0xa6, 0xcb, 0xb0, 0x34, 0x1e, 0x5e, 0x38, 0x72, 0x59, 0x65, 0x19, 0xb4, 0x1d, 0x82, 0x24, 0xa4, 0xd, 0x6, 0xe4, 0x67, 0x6, 0xa, 0x96, 0xcc, 0x8c, 0xfb, 0x3b, 0x45, 0xf2, 0xb9, 0x79, 0x34, 0xd1, 0x60, 0x82, 0xad, 0xe0, 0x12, 0x40, 0x36, 0x8c, 0x6c, 0x28, 0xfc, 0xaa, 0x9c, 0x48, 0xa0, 0x25, 0xca, 0x21, 0x5a, 0xbe, 0x98, 0xbc, 0xf5, 0x7b, 0x47, 0x8d, 0xb8, 0xf5, 0x2, 0xad, 0xd4, 0x6c, 0x47, 0x54, 0xa9, 0xd2, 0xef, 0xe9, 0xbb, 0x43, 0xaf, 0x6f, 0x69, 0x5, 0x2d, 0x1, 0xd9, 0xf, 0x22, 0x4d, 0xf6, 0x83, 0xe0, 0xa2, 0xb6, 0x3e, 0x51, 0x77, 0x80, 0x98, 0xe6, 0x49, 0x85, 0xca, 0xa3, 0x5, 0x53, 0x3f, 0x1a, 0x3b, 0x3e, 0x6c, 0x3f, 0xa5, 0x7e, 0x2b, 0x3d, 0x2, 0xdc, 0xbd, 0x34, 0xb6, 0xfb, 0xde, 0x38, 0xf5, 0x8c, 0x5e, 0x87, 0x94, 0x17, 0xe8, 0x19, 0xb4, 0xef, 0x9e, 0x66, 0x7c, 0x45, 0xf1, 0x89, 0x9c, 0xcf, 0xa9, 0x90, 0xec, 0x81, 0x34, 0x14, 0x22, 0xd6, 0x47, 0x28, 0x1, 0x64, 0xc4, 0xf8, 0xc1, 0x47, 0x77, 0x3d, 0x79, 0x4e, 0x6e, 0x6e, 0xfb, 0x96, 0x82, 0x35, 0x2, 0x57, 0x27, 0xa4, 0x75, 0x4d, 0x51, 0x98, 0xcf, 0x7d, 0xeb, 0xa9, 0x96, 0x3d, 0x27, 0x9e, 0x1e, 0xa, 0x5e, 0xff, 0xd1, 0xfe, 0x9c, 0xb, 0x71, 0x99, 0x8b, 0xbc, 0x4, 0x9e, 0x72, 0x31, 0xa3, 0xfe, 0x78, 0x3c, 0xec, 0xbb, 0xbf, 0x61, 0x34, 0xe, 0xe, 0xc8, 0xc0, 0xed, 0x29, 0xff, 0xce, 0x9e, 0x94, 0x1a, 0x1d, 0x92, 0x29, 0x72, 0x9e, 0xa9, 0x7f, 0x21, 0x72, 0xd5, 0xd2, 0x75, 0x34, 0x9f, 0xcf, 0x9f, 0xe2, 0xfc, 0x5, 0x8a, 0x53, 0x60, 0x81, 0xfe, 0x4, 0x47, 0x7a, 0x29, 0xaf, 0x81, 0x7f, 0xb1, 0x49, 0xe8, 0x77, 0x8c, 0x43, 0x6b, 0xe3, 0xc1, 0x6, 0xa5, 0xd3, 0xd1, 0xf4, 0x7, 0x97, 0xd0, 0x78, 0x33, 0xd5, 0x12, 0x98, 0x5, 0x2e, 0xbe, 0x70, 0x33, 0x65, 0x97, 0x18, 0x63, 0x88, 0x6f, 0xc6, 0x36, 0x44, 0xaf, 0x7d, 0x48, 0xb3, 0x20, 0xfa, 0x15, 0xb6, 0xfc, 0x3a, 0xfe, 0x7d, 0x97, 0x31, 0x8d, 0x6c, 0x4, 0x30, 0x66, 0xe5, 0x80, 0x85, 0xf9, 0x41, 0x5d, 0x4e, 0x8a, 0xaf, 0x70, 0x7, 0x19, 0x30, 0xd, 0xaf, 0xe1, 0xd1, 0x6f, 0x8, 0x96, 0x2c, 0x61, 0x30, 0xb1, 0x52, 0x60, 0xd9, 0x95, 0xa0, 0x1e, 0x88, 0x9a, 0xe2, 0xc, 0x74, 0xf5, 0x4b, 0xaa, 0x2, 0x91, 0xd0, 0xc, 0x2c, 0x65, 0x3c, 0x2c, 0x9f, 0xfb, 0xb6, 0x64, 0x2d, 0x1, 0xe, 0x28, 0x97, 0x7c, 0x6e, 0x4e, 0xa8, 0xa5, 0x9d, 0x3f, 0x6, 0x83, 0xa2, 0x92, 0x4b, 0xb4, 0xb2, 0x49, 0xad, 0xf, 0x1e, 0xd1, 0x34, 0xd5, 0xc8, 0x37, 0xce, 0xaa, 0xe3, 0xe1, 0x6d, 0x5f, 0x1b, 0x13, 0xa9, 0x1c, 0x2, 0x2, 0x3a, 0xea, 0x1a, 0x74, 0xd2, 0xa0, 0xde, 0x98, 0x3b, 0x8d, 0xc9, 0xe9, 0x30, 0x68, 0x6e, 0x75, 0x76, 0xc8, 0x25, 0x5b, 0xe5, 0x6b, 0x6b, 0xf6, 0xc5, 0x9e, 0x4d, 0x50, 0xe2, 0x70, 0x4d, 0xb2, 0x27, 0x6b, 0xec, 0x34, 0xb9, 0x9c, 0x41, 0xb6, 0x4f, 0x39, 0xb2, 0xd6, 0x7c, 0x7c, 0xac, 0x69, 0x9d, 0x7, 0xfd, 0xad, 0x3, 0xad, 0x35, 0x40, 0x19, 0x7e, 0x82, 0x9a, 0x2f, 0xd7, 0x54, 0xf8, 0x3b, 0xb7, 0xf5, 0x47, 0xc3, 0xe1, 0x30, 0xb8, 0x0, 0xbd, 0x86, 0x46, 0x18, 0xbc, 0x3a, 0x6c, 0xa1, 0x63, 0x25, 0x8d, 0xc6, 0x18, 0x67, 0x95, 0x10, 0x17, 0x2d, 0xc7, 0xdb, 0x56, 0xe9, 0x1a, 0xa8, 0x66, 0x4, 0x47, 0x7e, 0x95, 0x36, 0xec, 0x5f, 0xd9, 0xec, 0x2a, 0xc7, 0xbb, 0x90, 0xef, 0x6d, 0xe4, 0x39, 0x84, 0x60, 0x65, 0xce, 0xd, 0x17, 0xc4, 0x28, 0x81, 0x59, 0x72, 0x36, 0x3c, 0x3b, 0xb3, 0x8d, 0x7, 0x42, 0x46, 0x7c, 0x2d, 0xb, 0xfb, 0x34, 0xdd, 0x5e, 0x29, 0x9d, 0x3d, 0x71, 0x4c, 0x46, 0x81, 0x6d, 0x14, 0x1d, 0xdd, 0x2a, 0xcd, 0x5d, 0x30, 0x88, 0x74, 0xe3, 0xea, 0x81, 0x6, 0xa9, 0x35, 0x90, 0xba, 0x6d, 0xbf, 0xb1, 0x2d, 0xd4, 0xf9, 0xa3, 0xd5, 0xd2, 0x47, 0x17, 0xcf, 0x78, 0xd0, 0x7a, 0xcb, 0x58, 0x91, 0x67, 0x79, 0xc1, 0x32, 0x38, 0xc8, 0x6e, 0x4c, 0xd4, 0xa2, 0xf7, 0x4d, 0x90, 0xff, 0xdb, 0x2a, 0x53, 0xb5, 0xbb, 0xa5, 0x33, 0x6f, 0x5, 0xf3, 0x15, 0x6e, 0xd4, 0xd, 0xb, 0x89, 0xcf, 0xd6, 0x2a, 0xd8, 0xe5, 0xc8, 0x3d, 0x69, 0x27, 0x95, 0xd, 0xae, 0x2d, 0xf2, 0xce, 0x33, 0x29, 0x75, 0x1c, 0x3, 0x52, 0x84, 0x8c, 0x91, 0xe4, 0x7f, 0xb2, 0x67, 0xed, 0x48, 0x44, 0x2e, 0xd9, 0x13, 0x7e, 0xda, 0x81, 0x77, 0xe, 0x4c, 0x56, 0xf2, 0x22, 0x17, 0x2, 0x7c, 0xed, 0x47, 0x80, 0xef, 0x13, 0x55, 0x6e, 0x71, 0x16, 0xd3, 0x5, 0xbc, 0x80, 0xec, 0x79, 0xd5, 0xd, 0x6a, 0x17, 0x50, 0x97, 0x32, 0xed, 0xdb, 0x47, 0xad, 0x44, 0x5f, 0x42, 0xf6, 0x21, 0xa4, 0x69, 0x48, 0x79, 0xa5, 0x9a, 0x37, 0x84, 0x3a, 0xd5, 0x2f, 0x1e, 0x6c, 0xb5, 0x34, 0x7d, 0x52, 0xaf, 0xb1, 0x4c, 0xd0, 0x2f, 0x86, 0xf4, 0xa0, 0x2b, 0x6f, 0x27, 0xea, 0x26, 0xec, 0x5b, 0xdf, 0xcd, 0xe8, 0x0, 0x1c, 0xe8, 0xf7, 0x12, 0xc1, 0x93, 0xef, 0xbd, 0x7e, 0xef, 0x68, 0x77, 0xf5, 0x27, 0xb4, 0xd7, 0xdf, 0xb9, 0x94, 0xd9, 0x36, 0xc6, 0xa2, 0xa2, 0x84, 0xda, 0xcc, 0xd4, 0x47, 0xf3, 0x36, 0x6f, 0x31, 0x81, 0x8e, 0xc7, 0xfb, 0x5c, 0xe6, 0xf0, 0x8e, 0x45, 0x8d, 0xc5, 0xc6, 0x2, 0xe8, 0x7b, 0x89, 0x60, 0x50, 0x96, 0xe6, 0x25, 0xa0, 0xeb, 0x7c, 0xd2, 0x52, 0x14, 0xd8, 0x56, 0x74, 0x89, 0x77, 0x38, 0xbf, 0x67, 0x58, 0xad, 0x5b, 0x80, 0x5b, 0x2d, 0xb9, 0xc, 0xb0, 0xf, 0x3e, 0xda, 0x7f, 0xa2, 0xd7, 0xea, 0x1e, 0x6e, 0x9a, 0xbf, 0x93, 0xc6, 0x54, 0xf2, 0x7b, 0x48, 0x74, 0xb8, 0x90, 0x10, 0x91, 0x84, 0x2e, 0xe7, 0xc3, 0xeb, 0x1d, 0x54, 0xfc, 0x8a, 0xe8, 0x30, 0x91, 0xde, 0x31, 0x32, 0x5, 0x8d, 0x7a, 0x7c, 0xb0, 0x8a, 0x9e, 0x74, 0xda, 0xe3, 0xf8, 0xfe, 0x27, 0x9e, 0x83, 0x73, 0xbd, 0x79, 0xee, 0x60, 0x6d, 0x27, 0x46, 0xce, 0x2b, 0x7b, 0x47, 0x75, 0xd3, 0xa7, 0x1e, 0xaf, 0x86, 0x50, 0xf, 0xce, 0xc8, 0x5d, 0x8e, 0x6e, 0x86, 0xb7, 0x7a, 0x1d, 0xdf, 0xdc, 0x5a, 0x7, 0x69, 0x64, 0x77, 0xe3, 0x7c, 0x91, 0xbf, 0xfe, 0x36, 0xdd, 0x7f, 0xfb, 0x5c, 0xbb, 0xdf, 0x55, 0xca, 0xa8, 0xd9, 0xfa, 0xe0, 0xe2, 0xc6, 0xee, 0xdb, 0xea, 0xbc, 0x5a, 0x5d, 0x5e, 0x78, 0xfb, 0xc2, 0xff, 0xbc, 0xcc, 0xa0, 0x26, 0x70, 0x7c, 0x77, 0x1b, 0x91, 0xc5, 0x9f, 0x4e, 0x7d, 0x81, 0xef, 0xea, 0xff, 0x70, 0xd9, 0x7f, 0x6c, 0x4d, 0xf4, 0x3f, 0xdf, 0xa6, 0x7f, 0x1, 0xe3, 0x5, 0x57, 0x93, 0xde, 0x13, 0x0, 0x0, 0x0, 0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x8c, 0xba, 0x65, 0x50, 0x1c, 0x40, 0xd7, 0x35, 0x38, 0xb8, 0xc3, 0xe0, 0xee, 0xee, 0x83, 0x7b, 0x82, 0x3b, 0x4, 0xf7, 0x21, 0xb8, 0xdb, 0xa0, 0x41, 0x82, 0xbb, 0xbb, 0x13, 0x9c, 0xe0, 0x3a, 0x38, 0x24, 0xb8, 0x3b, 0x83, 0xbb, 0xbb, 0x5b, 0x20, 0xb6, 0x79, 0x9e, 0xef, 0x7d, 0xb7, 0x76, 0xab, 0xf6, 0xc7, 0x9e, 0xae, 0xba, 0x2d, 0x55, 0x7d, 0xbb, 0xcf, 0xfd, 0x71, 0x6e, 0xf5, 0xad, 0xfe, 0xbb, 0xfa, 0x77, 0x17, 0x0, 0x54, 0x96, 0x57, 0x92, 0x7, 0xc0, 0xc1, 0x1, 0x0, 0x70, 0xff, 0x1a, 0xe0, 0xef, 0x6, 0x20, 0x1c, 0x80, 0x87, 0x8d, 0x8d, 0xd, 0xc4, 0x26, 0x4, 0x2, 0x9, 0xa9, 0xf0, 0x71, 0xf1, 0xa9, 0xe8, 0xc9, 0x8, 0x9, 0xc9, 0xe8, 0xe9, 0x88, 0xff, 0x3, 0x3a, 0x5c, 0xcc, 0xff, 0xe2, 0x7f, 0xba, 0xff, 0x6f, 0xc0, 0x11, 0xe0, 0xe3, 0x13, 0x91, 0x12, 0x91, 0x13, 0x13, 0x93, 0x13, 0xfc, 0x73, 0x45, 0xf0, 0x1f, 0x83, 0x4d, 0xf0, 0x7f, 0xb6, 0xe0, 0xfe, 0xff, 0x71, 0xf0, 0x77, 0x0, 0x80, 0x8b, 0xa, 0x78, 0x85, 0x4b, 0x46, 0x80, 0xa3, 0x3, 0xc0, 0xe3, 0xc2, 0x21, 0xe0, 0xc2, 0xfd, 0x1d, 0x2, 0x90, 0x3, 0x0, 0xf0, 0x8, 0x70, 0xff, 0xb9, 0xea, 0xff, 0x2, 0x1, 0x11, 0xe, 0x1e, 0x9, 0x80, 0x8c, 0xf2, 0x77, 0x1d, 0x80, 0xfa, 0x7f, 0xd6, 0x1f, 0xe, 0xeb, 0x58, 0xe7, 0x5, 0x0, 0x47, 0x9, 0xe3, 0x7, 0xbe, 0xbd, 0x3a, 0xb1, 0xd3, 0x8b, 0xb4, 0xb1, 0x84, 0xd5, 0x3, 0x8d, 0xca, 0x93, 0x4, 0xb1, 0x68, 0xb1, 0x4, 0x14, 0xe, 0x27, 0xd, 0x5f, 0x21, 0xf1, 0x1e, 0xf3, 0xe6, 0xd1, 0x5f, 0xda, 0x5, 0xb2, 0xd2, 0xe9, 0x1c, 0x51, 0xf5, 0x69, 0x31, 0xfd, 0x18, 0x88, 0x88, 0x9a, 0x68, 0x9c, 0xf4, 0xa0, 0xf8, 0x96, 0xbc, 0x8b, 0x5e, 0x88, 0x2d, 0x4f, 0x5f, 0xa8, 0xbd, 0x9c, 0x35, 0x5c, 0xde, 0x30, 0x51, 0x48, 0x34, 0xc0, 0x16, 0xf4, 0x3a, 0x9e, 0x60, 0x8b, 0xce, 0x33, 0x12, 0x6, 0x7e, 0xd4, 0x2d, 0xcd, 0xaf, 0x65, 0xec, 0x8b, 0xd5, 0x1d, 0xc4, 0x8f, 0x13, 0x35, 0xb0, 0xc4, 0x3a, 0xdf, 0x1d, 0xe5, 0x19, 0xe4, 0xb2, 0x5a, 0x56, 0x4b, 0x4a, 0x62, 0x9d, 0x82, 0x2c, 0x66, 0x56, 0x52, 0x72, 0x4c, 0x6c, 0xb1, 0x4e, 0xaf, 0x47, 0x44, 0x65, 0x3b, 0x5b, 0x44, 0xfb, 0x9f, 0x10, 0x9b, 0x62, 0x2d, 0x74, 0x36, 0xf0, 0xda, 0x43, 0xde, 0x5, 0xf8, 0x9a, 0x26, 0x34, 0x4e, 0x70, 0x64, 0xe7, 0x2b, 0x47, 0x3a, 0x56, 0x58, 0xdf, 0xd, 0xb1, 0xa1, 0x4f, 0xd, 0x2f, 0xed, 0x16, 0x8f, 0x9f, 0x43, 0x84, 0x94, 0x69, 0xc9, 0xfb, 0xaf, 0xad, 0xaf, 0x4e, 0x9c, 0xe6, 0xd5, 0xb, 0x58, 0xa5, 0xc6, 0xab, 0xaf, 0xb3, 0xe5, 0xea, 0xb8, 0x46, 0xa2, 0x96, 0x7e, 0x4, 0xe4, 0x19, 0xf3, 0xc8, 0x86, 0x1f, 0x72, 0x6d, 0x5f, 0xcb, 0x5b, 0x90, 0x5c, 0x65, 0x3d, 0xd7, 0xb8, 0x2, 0x2b, 0x2c, 0xa4, 0xfd, 0x46, 0x47, 0xe6, 0xe5, 0x42, 0xce, 0xdc, 0x6e, 0x6f, 0xdc, 0xbc, 0x43, 0xa4, 0xb1, 0x98, 0xf8, 0x2a, 0xd7, 0x67, 0xb9, 0x22, 0x26, 0x5a, 0x2, 0xbc, 0xbb, 0x51, 0xfd, 0xe2, 0x31, 0xdf, 0x64, 0x1f, 0x5c, 0xd, 0xd8, 0x5a, 0x5b, 0x4f, 0xf4, 0x96, 0x74, 0x18, 0xde, 0x61, 0x67, 0x1a, 0x5e, 0x8b, 0x9, 0x41, 0x74, 0x7f, 0xd6, 0x76, 0x4f, 0x52, 0xd8, 0x2b, 0x81, 0xb5, 0xf2, 0x6d, 0xe7, 0xf8, 0x14, 0xb, 0x15, 0xf8, 0x92, 0xb8, 0x2a, 0xb1, 0xcc, 0xb0, 0x28, 0x4d, 0x78, 0x6d, 0xc8, 0x4d, 0x3b, 0xac, 0xf2, 0xf8, 0xf0, 0x97, 0xed, 0x4d, 0xc9, 0xab, 0x1e, 0x48, 0x23, 0xa, 0x54, 0xb5, 0xf5, 0xf8, 0xb9, 0xda, 0x5, 0x99, 0xae, 0x18, 0x3e, 0xa, 0xbf, 0xb, 0x5d, 0xbb, 0x6c, 0x60, 0xad, 0x35, 0xc7, 0x8d, 0x40, 0xb4, 0xcc, 0x70, 0x41, 0x11, 0x72, 0xac, 0x5e, 0x8f, 0xb5, 0xc7, 0xe2, 0x62, 0x9b, 0x89, 0x56, 0x13, 0xd2, 0x62, 0xc5, 0xb2, 0xaf, 0x9e, 0x78, 0x15, 0x3d, 0xb3, 0xb9, 0xa9, 0x6f, 0xdd, 0x78, 0xe8, 0x66, 0xe7, 0x6d, 0x56, 0x15, 0xd5, 0x88, 0xdc, 0x83, 0x53, 0x37, 0x27, 0x60, 0x69, 0x67, 0x31, 0xfd, 0x2a, 0xc0, 0x26, 0x9d, 0xca, 0xff, 0x20, 0x24, 0xc6, 0xeb, 0xa5, 0xdd, 0xda, 0xbc, 0x36, 0x4b, 0x5e, 0x45, 0x2d, 0x31, 0x66, 0x18, 0xc6, 0xf, 0xda, 0x69, 0x89, 0x3c, 0xc, 0x1e, 0xa9, 0x4e, 0xe7, 0x6d, 0xe1, 0x54, 0xbb, 0xf2, 0xcb, 0xa6, 0x6b, 0xf5, 0x1a, 0x20, 0xce, 0x45, 0xd6, 0x32, 0xcd, 0x8f, 0xa9, 0x7e, 0xc9, 0x73, 0x8a, 0x56, 0x36, 0xae, 0x75, 0x43, 0xd2, 0x4d, 0xd4, 0xf8, 0x58, 0xc3, 0xfa, 0x80, 0x11, 0x3f, 0xb, 0xb8, 0x7, 0x3d, 0xc4, 0xf5, 0x82, 0x65, 0xe5, 0xea, 0xbe, 0x24, 0x3c, 0xfe, 0x3a, 0xa9, 0x9f, 0x9e, 0xb5, 0xc2, 0x8b, 0x33, 0x4, 0x7f, 0x2d, 0xe3, 0xa7, 0xf9, 0x35, 0x96, 0x80, 0x5e, 0x6f, 0xce, 0xb1, 0x1e, 0x5e, 0x1a, 0x6a, 0x19, 0xda, 0x6a, 0xb2, 0x80, 0x99, 0x9a, 0x40, 0xc0, 0xf5, 0xea, 0x3c, 0xdf, 0x98, 0xcc, 0x69, 0xd0, 0xce, 0x9e, 0xfb, 0x41, 0x16, 0x7d, 0x1c, 0x6b, 0xcb, 0x1c, 0xbe, 0x78, 0xf6, 0x4, 0xc9, 0xba, 0xe3, 0x24, 0xf9, 0x58, 0xe0, 0x7b, 0x4e, 0x6d, 0x1d, 0xa3, 0x44, 0xf3, 0x2c, 0x93, 0x4, 0x47, 0x3f, 0x5e, 0x6b, 0x63, 0xb3, 0x79, 0x56, 0xe1, 0x59, 0xbb, 0x9c, 0xdf, 0xa4, 0x32, 0x5d, 0x95, 0x71, 0x9, 0x6, 0xbf, 0xa6, 0x2d, 0xdb, 0xf5, 0xb3, 0x65, 0xc2, 0xd3, 0x57, 0x39, 0x5, 0x87, 0x62, 0xf8, 0xc6, 0xe3, 0x8, 0xb2, 0x2c, 0xa5, 0xcd, 0x59, 0x85, 0x62, 0xe5, 0x61, 0xcb, 0xc8, 0x1e, 0x4d, 0xda, 0x16, 0x3f, 0x5b, 0xd1, 0xef, 0xe8, 0x24, 0xf6, 0x53, 0x60, 0x1f, 0xd9, 0xb7, 0xf5, 0x89, 0x39, 0x1f, 0x73, 0x93, 0x76, 0xe2, 0xae, 0x30, 0xef, 0x1c, 0x9, 0xf, 0x1, 0x28, 0x8f, 0x7e, 0x9d, 0xdc, 0xc4, 0x37, 0x27, 0x6c, 0xf6, 0x12, 0xe4, 0x1c, 0x91, 0x6, 0x86, 0x1, 0x4b, 0xee, 0x5, 0x15, 0x5f, 0xd1, 0x36, 0x30, 0x32, 0xca, 0x91, 0xca, 0x76, 0x1d, 0x80, 0xa8, 0x11, 0x6a, 0x76, 0x43, 0x6c, 0xed, 0xfb, 0x5d, 0xb2, 0x2e, 0x1b, 0xf0, 0x20, 0x54, 0xe7, 0x73, 0xdc, 0x4b, 0x7f, 0xb1, 0x4b, 0x2d, 0x63, 0xd7, 0xe9, 0x2c, 0xad, 0x63, 0xac, 0xfb, 0x17, 0x40, 0x7a, 0xda, 0x44, 0x9b, 0xbb, 0x15, 0x70, 0xc, 0xf3, 0xd2, 0xf3, 0x7e, 0x13, 0xb1, 0xe6, 0xf3, 0x70, 0x2d, 0x52, 0xc8, 0x6a, 0x15, 0x22, 0xe1, 0x87, 0xe5, 0x73, 0xb, 0xb0, 0x39, 0x5c, 0x8a, 0x76, 0xcc, 0x24, 0xd2, 0xf8, 0x34, 0x7a, 0xf1, 0xb5, 0x12, 0xd2, 0x81, 0xb8, 0xf8, 0x7d, 0x5f, 0x5a, 0xdb, 0xde, 0xb6, 0x5d, 0x51, 0x2a, 0x38, 0x54, 0x9c, 0x8c, 0xfe, 0x24, 0x2f, 0x17, 0x71, 0x81, 0xbe, 0x9e, 0x9c, 0x68, 0x7f, 0x60, 0x5e, 0xec, 0x6f, 0xf9, 0x80, 0x19, 0xed, 0x7b, 0x1a, 0x5e, 0x77, 0x3c, 0x8a, 0xb6, 0x2e, 0x96, 0x8c, 0xf3, 0x69, 0x74, 0x12, 0x69, 0x11, 0xb4, 0xd0, 0x45, 0xd6, 0x37, 0x1f, 0x6b, 0x5c, 0x9e, 0xe9, 0xca, 0x62, 0xe6, 0xf4, 0xb5, 0xf4, 0x54, 0x4, 0x89, 0x5b, 0xc3, 0x66, 0x85, 0xf, 0x66, 0x3e, 0x18, 0x2b, 0xeb, 0xb4, 0xeb, 0xba, 0xcb, 0xd9, 0x76, 0x93, 0x78, 0x4d, 0x73, 0x65, 0x4a, 0xcf, 0xed, 0xd7, 0x4e, 0xd6, 0x93, 0xfe, 0x12, 0xbf, 0x93, 0x9e, 0xb5, 0xf4, 0x9a, 0x50, 0xde, 0x26, 0x37, 0xf4, 0xcd, 0xb1, 0x15, 0x9d, 0x23, 0x8e, 0x35, 0x97, 0xd2, 0x53, 0x2, 0x59, 0x7d, 0x9a, 0x8, 0x68, 0x6, 0x93, 0xf4, 0x40, 0xd9, 0x79, 0xa3, 0x96, 0x94, 0xcc, 0x7d, 0x64, 0xf0, 0x55, 0x49, 0x13, 0xf2, 0x99, 0x16, 0xf1, 0x5a, 0x6b, 0xa8, 0x52, 0x99, 0x7d, 0xb, 0xe8, 0x39, 0xe1, 0x85, 0xfa, 0xee, 0xf0, 0x2e, 0x52, 0x25, 0xa1, 0x51, 0xab, 0x7, 0xdb, 0x3c, 0x7f, 0x0, 0x51, 0x96, 0x7d, 0xd4, 0x88, 0xb6, 0x40, 0xbd, 0x40, 0x81, 0x4, 0x9, 0xe4, 0xb4, 0x1c, 0xc7, 0x35, 0x68, 0x9d, 0xe8, 0x1b, 0xbb, 0x62, 0x5, 0x7c, 0xd0, 0xce, 0x2c, 0x59, 0x7f, 0xd7, 0x4d, 0xfc, 0x9e, 0xd8, 0x98, 0x7a, 0xc9, 0xfa, 0x4d, 0xb5, 0xc9, 0xc1, 0x76, 0x37, 0xec, 0xab, 0x6c, 0x97, 0x53, 0x9b, 0xc5, 0xfc, 0x35, 0xc1, 0x68, 0x61, 0x6c, 0x11, 0x56, 0xbe, 0x14, 0xed, 0xf6, 0xcb, 0xec, 0xa9, 0x4d, 0xa, 0x25, 0xc5, 0xb1, 0xd1, 0x93, 0xf4, 0xc8, 0x43, 0xed, 0xb1, 0xf3, 0xd7, 0xee, 0x42, 0x67, 0x8a, 0xcd, 0xf5, 0x92, 0xc9, 0x69, 0x3b, 0xbc, 0xa6, 0xe5, 0xb3, 0x2a, 0xb4, 0xfc, 0xd6, 0x2, 0x29, 0x62, 0xcd, 0x69, 0xe6, 0xde, 0x7e, 0x7b, 0xcb, 0x18, 0xaa, 0x9a, 0x9f, 0x68, 0x73, 0x18, 0x56, 0xa0, 0xed, 0x36, 0x15, 0x83, 0x84, 0x4, 0x3a, 0x89, 0x1a, 0x8e, 0xe9, 0x9a, 0x2d, 0x82, 0xec, 0xce, 0x9c, 0xa1, 0x9, 0x5f, 0x9b, 0x9f, 0xb3, 0xd4, 0x6b, 0x7, 0xa7, 0x36, 0x28, 0x86, 0x2, 0x40, 0x7a, 0xef, 0x62, 0xb6, 0x9e, 0xcd, 0x38, 0x2e, 0x51, 0x70, 0xc5, 0x13, 0x83, 0xd3, 0x76, 0x6b, 0x62, 0x39, 0xbb, 0xb1, 0x6a, 0x7d, 0x65, 0xe, 0xfc, 0xa3, 0xf1, 0xd6, 0x6b, 0x6a, 0x66, 0x2a, 0x66, 0x6a, 0x9b, 0xd6, 0xb6, 0xdf, 0x96, 0x7d, 0x6c, 0xac, 0xb3, 0x42, 0x34, 0x89, 0x1d, 0x4, 0x77, 0x71, 0xe0, 0xb4, 0xe2, 0x8b, 0xf8, 0xf4, 0x12, 0x5e, 0xbc, 0xb, 0x57, 0x3c, 0xde, 0x4b, 0xc6, 0xb8, 0x6f, 0x9e, 0x1e, 0xe7, 0x52, 0xab, 0xdd, 0xf6, 0xbb, 0xa6, 0x10, 0xb7, 0xbc, 0x3a, 0x95, 0xa4, 0x30, 0x63, 0x2, 0x6e, 0x98, 0x8a, 0x7b, 0x73, 0xd8, 0xba, 0x19, 0x59, 0x2e, 0x5a, 0x41, 0xcf, 0xcf, 0xd4, 0x54, 0x45, 0x6, 0xfd, 0xba, 0x7e, 0x67, 0xb0, 0xf0, 0xc, 0xef, 0xf7, 0x7f, 0xc2, 0x45, 0x2, 0x7, 0x40, 0xf8, 0x7f, 0xca, 0xd6, 0x3f, 0xad, 0x85, 0x47, 0x0, 0x20, 0xfe, 0x57, 0xb5, 0xe0, 0x81, 0xff, 0xa6, 0x87, 0x9c, 0x39, 0x27, 0x7c, 0xaa, 0x39, 0xe, 0x84, 0x8a, 0x16, 0x48, 0x87, 0x68, 0x74, 0x10, 0xf, 0xa7, 0xe6, 0x36, 0x5d, 0x91, 0xdb, 0xa5, 0x34, 0x61, 0xa5, 0xfa, 0xa9, 0x3d, 0x2f, 0x5e, 0x84, 0x18, 0x56, 0xd9, 0xd2, 0x51, 0x25, 0x1c, 0xe9, 0x8e, 0x4, 0x3, 0x1a, 0xcd, 0xea, 0x31, 0xa2, 0x2b, 0xe, 0xcb, 0x82, 0x87, 0x53, 0x1d, 0x60, 0xda, 0x32, 0xd, 0x8a, 0x2f, 0x74, 0x6f, 0xde, 0xbe, 0xa9, 0xdf, 0xe6, 0x90, 0x6d, 0x2e, 0x21, 0xbf, 0x32, 0xbb, 0xd5, 0xf7, 0xc8, 0x2f, 0x22, 0x82, 0x77, 0xdf, 0x1b, 0x73, 0xc4, 0xc, 0x3, 0x5b, 0xeb, 0x5, 0x76, 0x8c, 0x8e, 0xc4, 0x1a, 0x86, 0xc2, 0x16, 0xa1, 0x14, 0x52, 0xce, 0xc7, 0x2d, 0x8a, 0xaf, 0x5, 0x49, 0x8d, 0xec, 0x6, 0x90, 0xc2, 0x42, 0xf5, 0x73, 0xb0, 0x36, 0x55, 0x87, 0xf6, 0xe6, 0x6, 0xe9, 0x41, 0xd6, 0xee, 0xf, 0x87, 0xed, 0x4a, 0xe3, 0x68, 0x20, 0x73, 0x6b, 0xdf, 0x8a, 0xe, 0x2, 0x2, 0xbe, 0x51, 0x9e, 0x50, 0xb4, 0xfa, 0x53, 0xdb, 0x2f, 0x4, 0xd2, 0xb7, 0xdd, 0xce, 0xd1, 0xa0, 0x50, 0xfc, 0x2a, 0xb5, 0x5a, 0xe6, 0xd8, 0x69, 0x3f, 0x16, 0x6c, 0xf0, 0x4c, 0xf6, 0xbe, 0x69, 0x48, 0xba, 0xe0, 0x2, 0x69, 0xf6, 0xd1, 0x17, 0xc4, 0xaa, 0x25, 0x37, 0x1d, 0x90, 0x9c, 0x5, 0x68, 0xd5, 0xf5, 0xbf, 0x34, 0xff, 0x8b, 0xff, 0x17, 0xcd, 0x7f, 0x12, 0xfd, 0x5f, 0x9a, 0x8, 0xff, 0xa1, 0xf9, 0x88, 0xcc, 0xb4, 0x85, 0x45, 0x38, 0x6d, 0x92, 0x96, 0xdd, 0xdb, 0xc6, 0x5e, 0x76, 0xed, 0xd7, 0x5, 0x59, 0xca, 0xc4, 0x1c, 0x35, 0x28, 0xd0, 0x55, 0x4f, 0xd3, 0x44, 0x51, 0x6b, 0x62, 0x74, 0x10, 0xf1, 0x5c, 0xf2, 0xcf, 0x24, 0x8f, 0xb1, 0xf7, 0x98, 0x71, 0x81, 0x4e, 0xe7, 0x3e, 0xce, 0x60, 0x27, 0x5f, 0x6e, 0x8c, 0x39, 0xe2, 0x5b, 0x7f, 0x7c, 0xa7, 0x47, 0xea, 0xa2, 0xa0, 0x83, 0x11, 0x9a, 0xbb, 0xf9, 0xfa, 0x54, 0xef, 0xf1, 0xc1, 0xd4, 0xaf, 0x89, 0xa9, 0x8e, 0x71, 0x79, 0x73, 0xbb, 0x59, 0xd2, 0xdb, 0x68, 0x7e, 0x4a, 0x39, 0xb4, 0x56, 0xcd, 0x5d, 0x51, 0x62, 0xab, 0x73, 0x2c, 0xcb, 0x20, 0xc6, 0x9b, 0x74, 0x3, 0xc7, 0x6f, 0xb3, 0xd8, 0x47, 0xdb, 0xc5, 0x6c, 0xce, 0x5e, 0x9a, 0xbb, 0x7, 0xb2, 0x76, 0x36, 0xd7, 0x67, 0xb1, 0x85, 0x9c, 0xc9, 0x34, 0x5f, 0xb0, 0x90, 0xeb, 0x23, 0xc2, 0x3a, 0x2f, 0xb5, 0x98, 0xef, 0xdc, 0xec, 0x75, 0x7e, 0x6a, 0xa1, 0x45, 0x36, 0xe8, 0xca, 0xca, 0x67, 0x5c, 0x6e, 0x3e, 0xca, 0x87, 0x8e, 0xd5, 0x25, 0x65, 0xbf, 0x5a, 0x74, 0xc2, 0xd5, 0x2b, 0x9a, 0xe6, 0x5c, 0xe3, 0xfc, 0x8f, 0xd, 0x27, 0x10, 0x0, 0xf, 0xf, 0xf, 0x87, 0xf0, 0x2f, 0xc7, 0x20, 0x22, 0xc0, 0xfd, 0xdf, 0x6c, 0x70, 0xf1, 0xf0, 0x69, 0x79, 0x80, 0x4, 0x74, 0x48, 0xf4, 0xbc, 0x52, 0x9a, 0x84, 0x34, 0xc, 0x7c, 0xfc, 0xd2, 0x32, 0xe6, 0xff, 0x93, 0x7f, 0xe0, 0xfe, 0x19, 0x2f, 0xe1, 0xda, 0x85, 0x1, 0x22, 0x3b, 0x35, 0x8e, 0xb9, 0x5c, 0xc3, 0xf5, 0x77, 0x45, 0x8f, 0x25, 0x89, 0x55, 0xc, 0xad, 0xac, 0xb7, 0x27, 0x4f, 0xfc, 0x72, 0xca, 0x3f, 0x2c, 0x7b, 0xf9, 0x77, 0xf3, 0x38, 0x6, 0xa1, 0x46, 0xf1, 0xcb, 0x1b, 0x8e, 0x60, 0x1f, 0xc6, 0x99, 0xc3, 0xd8, 0x60, 0x83, 0x58, 0xf6, 0xfa, 0xf1, 0x2e, 0x4d, 0x4, 0xf4, 0xdc, 0x3c, 0x7a, 0xbd, 0xe4, 0xea, 0x6b, 0x24, 0x3, 0x42, 0x66, 0xc4, 0xf8, 0x38, 0xf4, 0x5a, 0xf4, 0x96, 0xd8, 0x51, 0xc, 0x42, 0x3d, 0x88, 0xe1, 0x90, 0x1a, 0xd7, 0x2e, 0x5a, 0xa5, 0xae, 0x2d, 0x61, 0x84, 0x1e, 0xa0, 0x3b, 0x42, 0x8f, 0x8d, 0x35, 0x82, 0x40, 0x9d, 0x5d, 0xb8, 0xd6, 0x1a, 0x8c, 0x66, 0xae, 0x66, 0x7, 0x9, 0xbb, 0xf, 0x7e, 0xce, 0xaf, 0xd8, 0xcb, 0xfb, 0x87, 0x47, 0x90, 0x77, 0x6c, 0x4f, 0x62, 0xb9, 0xb8, 0x80, 0x29, 0xff, 0x5b, 0xdc, 0xd, 0xeb, 0x70, 0xd5, 0x62, 0xcb, 0xd9, 0xc5, 0x75, 0x6d, 0xd, 0xe1, 0xdd, 0xf2, 0x72, 0xc3, 0xbb, 0xd0, 0x2d, 0xf4, 0x3f, 0x2, 0x26, 0x31, 0xba, 0x9d, 0x17, 0x4b, 0x67, 0xf9, 0x35, 0xf3, 0xa8, 0x55, 0x9a, 0x84, 0x26, 0x9c, 0x99, 0x5a, 0xb0, 0xb6, 0x92, 0xed, 0xc1, 0x16, 0x77, 0x3d, 0x89, 0x70, 0xa0, 0x3c, 0x6e, 0x11, 0xdf, 0xe7, 0x52, 0xdf, 0xb8, 0xd3, 0xcf, 0x88, 0xa0, 0xe9, 0x3e, 0xff, 0xc1, 0x7d, 0x84, 0xca, 0x6d, 0x9, 0x83, 0x73, 0x9e, 0x4d, 0x26, 0xd7, 0x9e, 0xcd, 0x9d, 0xfa, 0xef, 0xd0, 0xc1, 0x63, 0x6d, 0x83, 0x7a, 0xa8, 0x3b, 0x6c, 0xe3, 0x46, 0xf4, 0xf9, 0x3d, 0xac, 0x2b, 0x4c, 0xed, 0x9, 0x79, 0xa1, 0x4c, 0x80, 0xfc, 0x5b, 0x81, 0x11, 0xa3, 0x30, 0x7c, 0x1a, 0xcc, 0xaf, 0x85, 0xa3, 0x85, 0xa6, 0x32, 0xc0, 0xa8, 0xce, 0x9d, 0xf1, 0x71, 0x2e, 0xba, 0xd7, 0x93, 0xe4, 0x95, 0x0, 0x5b, 0x50, 0xff, 0xe1, 0x9c, 0x9e, 0x99, 0xcd, 0x57, 0xf9, 0x15, 0x39, 0xa3, 0x23, 0x88, 0x2c, 0x58, 0x5a, 0x4c, 0xa1, 0xb0, 0xb3, 0xc3, 0x2c, 0x37, 0x6a, 0x8e, 0xe4, 0x33, 0x99, 0x6b, 0xcf, 0xef, 0xf, 0xdb, 0xbd, 0x9e, 0x1, 0xb3, 0xa0, 0x37, 0x6a, 0xbe, 0xe2, 0x75, 0x1, 0xbe, 0x10, 0xaa, 0xbc, 0xa7, 0x77, 0x1d, 0xd0, 0xa8, 0x96, 0x23, 0x6f, 0xd1, 0xd, 0x5, 0xb6, 0x44, 0x30, 0xdb, 0x1, 0x69, 0x21, 0x2e, 0xdb, 0x8c, 0x9a, 0xd5, 0xed, 0x54, 0x19, 0xa7, 0x21, 0x51, 0x3d, 0x17, 0xb, 0x7a, 0xe4, 0xe4, 0xdd, 0x78, 0xfb, 0xda, 0x63, 0x35, 0x1b, 0xbb, 0xe9, 0x47, 0xdf, 0xbf, 0x80, 0xf5, 0xc8, 0x6e, 0x3f, 0x9, 0xc, 0xd4, 0x2, 0xa1, 0xba, 0x27, 0xdc, 0xe0, 0xca, 0x50, 0xea, 0x32, 0x99, 0xe1, 0x79, 0xf, 0xb, 0xad, 0x2d, 0xf5, 0xc9, 0x89, 0xba, 0x73, 0xde, 0x2a, 0xad, 0xb1, 0xdb, 0xd7, 0xc7, 0xdf, 0xc3, 0xf, 0x2, 0x64, 0x70, 0x2, 0xa7, 0xb2, 0xf6, 0xf5, 0x77, 0x1f, 0xec, 0x7f, 0x46, 0x2d, 0x66, 0x91, 0x59, 0x64, 0x1f, 0x1c, 0xe1, 0xd8, 0xcd, 0xa3, 0xd2, 0xc8, 0x4b, 0x51, 0x9a, 0x3, 0x19, 0xd8, 0x98, 0x49, 0xf4, 0x1c, 0x0, 0x8c, 0x24, 0x43, 0xc1, 0x71, 0x2a, 0x6, 0x6d, 0x19, 0x39, 0x3a, 0xad, 0x7a, 0xb7, 0x22, 0x6d, 0x9e, 0x8d, 0xe7, 0xb5, 0x7, 0xc6, 0x57, 0x77, 0xbe, 0x82, 0xa, 0xdb, 0x9d, 0xbe, 0x96, 0xcb, 0xe7, 0x15, 0x17, 0x6c, 0x72, 0xb6, 0x96, 0xd6, 0xd3, 0xce, 0x32, 0x7b, 0x50, 0x6, 0x92, 0xed, 0xa5, 0xb9, 0x5c, 0x98, 0xa1, 0x31, 0xc4, 0x82, 0xd5, 0xfa, 0x7, 0x38, 0xd4, 0xb4, 0xe8, 0x42, 0x9a, 0xa7, 0x3d, 0xb6, 0x84, 0xa9, 0x83, 0x95, 0xb3, 0x8e, 0x53, 0xb0, 0x5d, 0x43, 0x25, 0xa, 0x83, 0xf4, 0x33, 0x26, 0xd0, 0x71, 0x3e, 0xca, 0x8e, 0x5c, 0xdb, 0x2d, 0x5a, 0x5c, 0xfe, 0x51, 0x73, 0x1d, 0xf1, 0xd0, 0x8b, 0x43, 0xeb, 0x8b, 0x63, 0x59, 0x61, 0x7a, 0x63, 0xc1, 0x39, 0x7, 0xdb, 0x87, 0x50, 0xff, 0xe7, 0x26, 0xd2, 0x80, 0xe2, 0x1f, 0xd1, 0xa6, 0x54, 0x77, 0x99, 0x2e, 0x2e, 0x2e, 0xf8, 0x6c, 0x75, 0x24, 0xd7, 0x30, 0x23, 0xa2, 0x92, 0x45, 0xb2, 0xdc, 0xcc, 0x45, 0xab, 0xb2, 0xd5, 0x9a, 0xee, 0x9c, 0x1a, 0xcb, 0x6d, 0x58, 0x5d, 0xed, 0xb9, 0xc1, 0xce, 0xa1, 0x2d, 0xa3, 0xfb, 0xb6, 0x2e, 0x95, 0x63, 0xe2, 0xb4, 0xab, 0xa6, 0xb3, 0x35, 0xe1, 0x45, 0x92, 0x42, 0xa5, 0x17, 0x38, 0xf3, 0x32, 0xc, 0xec, 0xf5, 0x24, 0x79, 0x4e, 0xff, 0xeb, 0x79, 0x45, 0xc2, 0x66, 0xe, 0x78, 0xb4, 0x89, 0x5a, 0x5f, 0x2e, 0xae, 0xa0, 0x66, 0x74, 0x4d, 0x1f, 0x6b, 0xe8, 0x48, 0x2d, 0xbc, 0x19, 0x93, 0xb9, 0x36, 0x31, 0x20, 0xf9, 0x2f, 0xde, 0x69, 0x9a, 0x2b, 0x3d, 0x6, 0x28, 0x76, 0xb2, 0x74, 0x4, 0xd1, 0x62, 0x72, 0x3f, 0x1a, 0x79, 0xb7, 0x78, 0x5d, 0xb8, 0xdf, 0xba, 0xb3, 0x43, 0x69, 0x2c, 0xc, 0x58, 0xc8, 0x5b, 0xa2, 0xa7, 0x1b, 0x42, 0xe0, 0x11, 0xee, 0xf0, 0x63, 0x36, 0x75, 0x12, 0x9b, 0xa2, 0x91, 0xc9, 0x19, 0xcd, 0x56, 0xfb, 0xa5, 0x86, 0x47, 0x46, 0xf7, 0x60, 0xca, 0x4d, 0x2f, 0xe6, 0xa5, 0x40, 0xc, 0x1e, 0xce, 0xe3, 0xd5, 0x27, 0xb, 0x3, 0xde, 0x63, 0x63, 0xe0, 0x50, 0xac, 0x8b, 0x96, 0xb7, 0xaf, 0x5e, 0x10, 0xfb, 0x1c, 0xd5, 0xfe, 0x54, 0x7e, 0xd2, 0xef, 0xae, 0x1c, 0x54, 0xa2, 0x62, 0xeb, 0xba, 0xfa, 0x82, 0xb1, 0x41, 0x32, 0x98, 0x31, 0xbb, 0xa0, 0x8e, 0x3b, 0xa0, 0x86, 0xf9, 0xd0, 0xd3, 0x61, 0x90, 0x54, 0x82, 0x5c, 0x78, 0x9f, 0xb3, 0x87, 0x4b, 0x82, 0xb0, 0xa7, 0xb, 0x19, 0xf0, 0x8b, 0x30, 0xed, 0x23, 0x57, 0x22, 0x5f, 0xf6, 0x47, 0xb2, 0xfa, 0x89, 0x4d, 0x9f, 0x3b, 0xaa, 0x4, 0x22, 0x86, 0xed, 0x52, 0x12, 0x9c, 0x4f, 0xc9, 0x95, 0x30, 0x73, 0x21, 0xb6, 0xeb, 0xa, 0xc3, 0x75, 0x9c, 0x27, 0x15, 0x31, 0x7d, 0x94, 0xe8, 0x52, 0xdb, 0x4e, 0x17, 0xcc, 0x4f, 0xb, 0xef, 0x6e, 0xb, 0x35, 0xef, 0x31, 0xb5, 0x11, 0xe4, 0x2, 0xef, 0x67, 0xf6, 0x8d, 0x52, 0xe3, 0x7d, 0xba, 0xfa, 0xe2, 0xac, 0x6d, 0xba, 0x9d, 0x9, 0xd1, 0x93, 0xf7, 0x31, 0xd4, 0x88, 0xb6, 0x62, 0xc2, 0x60, 0xa4, 0x8e, 0x9f, 0xb7, 0x97, 0x63, 0xb2, 0x62, 0xb3, 0xb4, 0xc1, 0x4, 0x5b, 0x1f, 0xc9, 0x3a, 0xc2, 0x12, 0x9c, 0x1b, 0x8a, 0xb2, 0x7, 0x13, 0x53, 0xaa, 0x65, 0x29, 0xab, 0xe1, 0xe0, 0x98, 0x29, 0x4d, 0xbf, 0xa, 0xd6, 0x37, 0x4b, 0x69, 0x6c, 0xf2, 0x4c, 0x8f, 0xfc, 0xe0, 0x3a, 0xb8, 0xe6, 0x45, 0x4a, 0x68, 0x3b, 0xec, 0xb8, 0xd0, 0x53, 0x93, 0x8f, 0x6a, 0x25, 0xac, 0x7d, 0xe1, 0x37, 0xc8, 0xd4, 0xf1, 0x5d, 0xd2, 0x53, 0x13, 0xf8, 0x4e, 0x1a, 0x44, 0x49, 0xac, 0xde, 0x79, 0xb4, 0x39, 0xf, 0x1e, 0x87, 0x55, 0x73, 0x17, 0x7, 0x4b, 0x61, 0x3a, 0xf, 0x3, 0xbd, 0xf1, 0x2b, 0xe9, 0x7d, 0x22, 0x35, 0xf7, 0x8d, 0x59, 0xc4, 0xc0, 0x2a, 0xdf, 0xa9, 0x25, 0xb7, 0x8e, 0xa6, 0xea, 0xea, 0xf9, 0x2d, 0x3d, 0x1a, 0x72, 0x8f, 0x9a, 0x58, 0x2b, 0x7e, 0xab, 0xcb, 0xb3, 0xab, 0x5d, 0x59, 0x46, 0xaf, 0x51, 0x22, 0xe8, 0xaa, 0xe4, 0xe9, 0xc9, 0xac, 0x22, 0x31, 0x78, 0x36, 0x54, 0x11, 0xb, 0xb1, 0x92, 0x48, 0xb0, 0x75, 0xa, 0x16, 0xf, 0xd5, 0x6b, 0x82, 0x7b, 0x39, 0x5a, 0xb4, 0x75, 0x33, 0x92, 0xe4, 0x2f, 0xea, 0xa, 0xaa, 0xf4, 0x1a, 0x5, 0x36, 0x36, 0x56, 0x3e, 0x72, 0x77, 0xac, 0x58, 0x57, 0xd7, 0x57, 0x8f, 0x6c, 0x18, 0xbe, 0x70, 0xd4, 0x45, 0xfb, 0x20, 0x35, 0x62, 0x3, 0x33, 0xe7, 0x13, 0x9f, 0x30, 0x6a, 0x24, 0x3a, 0x8e, 0x2a, 0xff, 0x2, 0xc8, 0xc9, 0xf3, 0x1d, 0x79, 0xa, 0x86, 0xaf, 0xd2, 0xf4, 0xd9, 0x34, 0x75, 0xb5, 0xaf, 0x30, 0xf4, 0x4a, 0xb4, 0x1f, 0xce, 0xe, 0x8c, 0xe0, 0xe0, 0x12, 0x74, 0xd, 0x98, 0xba, 0x5f, 0x1e, 0x31, 0x84, 0x7, 0x68, 0x22, 0xb9, 0x8a, 0x1, 0x31, 0x95, 0xe6, 0x19, 0x9, 0x68, 0xae, 0x39, 0xf1, 0xfe, 0xe7, 0x86, 0x5b, 0x8a, 0xb9, 0x3c, 0x8c, 0xd5, 0x42, 0xeb, 0xf1, 0x5f, 0xd8, 0x8, 0x3d, 0xb0, 0x22, 0xc6, 0x5d, 0x61, 0x20, 0xaa, 0x3b, 0x4c, 0xc8, 0x3a, 0xd2, 0x89, 0x1f, 0xbf, 0x6a, 0xfe, 0xa4, 0x5a, 0x89, 0x86, 0xe3, 0xf0, 0xf0, 0x47, 0x4f, 0xfb, 0x11, 0x5, 0x7f, 0xe7, 0xb7, 0x88, 0xf, 0xd5, 0xee, 0x55, 0xe3, 0x2f, 0x14, 0xa7, 0x5d, 0x71, 0xae, 0x15, 0xdd, 0x23, 0xc, 0x13, 0xab, 0x2b, 0x64, 0x77, 0x51, 0x8e, 0x1c, 0xed, 0xf4, 0x1, 0x29, 0xe, 0x55, 0x32, 0x3a, 0xd7, 0x90, 0x7c, 0x31, 0xd1, 0x63, 0x76, 0xe3, 0x24, 0x6b, 0xcb, 0xd2, 0xd8, 0x55, 0xb6, 0x87, 0x8, 0x91, 0x8e, 0xa7, 0xf0, 0x23, 0x15, 0x23, 0xae, 0x74, 0xe1, 0x8a, 0xee, 0x7b, 0xda, 0xe7, 0xab, 0x10, 0xcb, 0x72, 0xa1, 0x8c, 0x52, 0x29, 0xd3, 0xea, 0xa5, 0xbe, 0xe7, 0x4c, 0x61, 0x4c, 0x18, 0xa5, 0x90, 0xe3, 0x70, 0xd2, 0x47, 0x5a, 0x5b, 0x8f, 0xef, 0x92, 0x8d, 0xdc, 0xc5, 0x8f, 0xc, 0x7d, 0xf3, 0xc6, 0x50, 0xca, 0x27, 0x52, 0x7f, 0x69, 0xa6, 0x47, 0x7a, 0x9f, 0xe0, 0xe4, 0xad, 0x94, 0x57, 0x34, 0xef, 0x50, 0xc9, 0x21, 0xb5, 0x34, 0xdc, 0xd8, 0xc9, 0xbc, 0x74, 0x2a, 0x7a, 0x3f, 0xbd, 0xc5, 0xcf, 0xc5, 0x9d, 0x72, 0xb6, 0x24, 0xe6, 0x1f, 0xc1, 0xec, 0x6d, 0x63, 0x27, 0x81, 0xe0, 0x8c, 0x77, 0x72, 0x98, 0xe9, 0x8b, 0xe0, 0x4e, 0x41, 0xc3, 0x24, 0x79, 0x16, 0xfd, 0x89, 0x6f, 0xd5, 0x75, 0x8d, 0xfa, 0x81, 0x5c, 0x5a, 0x2, 0x9d, 0xe8, 0x4b, 0x1b, 0x6, 0x7b, 0xc9, 0x2a, 0x5c, 0x69, 0xf8, 0xd1, 0x3e, 0x47, 0xba, 0x6d, 0x1b, 0x32, 0xeb, 0xad, 0xe4, 0xba, 0x97, 0x6, 0xd3, 0x93, 0x38, 0x7, 0x8f, 0xf3, 0xfa, 0x2d, 0xd6, 0xad, 0x7f, 0xa, 0x5a, 0x3b, 0x17, 0xa6, 0xf4, 0xd6, 0xef, 0x3, 0x7c, 0x9a, 0xa6, 0x51, 0xb7, 0xe8, 0xc1, 0x1d, 0x31, 0xca, 0x46, 0x9a, 0x1d, 0xfa, 0xea, 0xa, 0x3c, 0x26, 0x63, 0xe5, 0x77, 0xf3, 0x0, 0x82, 0x60, 0xb9, 0xf3, 0xe5, 0x2e, 0x83, 0x9e, 0x94, 0x99, 0x35, 0xba, 0xe8, 0x12, 0x5c, 0xb4, 0xdc, 0x60, 0xf9, 0x2b, 0xc4, 0x4d, 0xd3, 0xb9, 0x9e, 0x7b, 0xcb, 0x4f, 0x89, 0xa8, 0x1a, 0x16, 0xc1, 0x6, 0xca, 0xd1, 0x6b, 0x78, 0xf, 0xab, 0x7e, 0x8, 0x67, 0x7e, 0xc1, 0xc1, 0xfd, 0xbb, 0x32, 0xc2, 0xc3, 0x60, 0x12, 0x1b, 0x8b, 0xe0, 0xf1, 0x74, 0x4e, 0xe5, 0x2b, 0x7e, 0xb2, 0xeb, 0xfe, 0x77, 0x17, 0x9b, 0xd, 0x38, 0x5e, 0xd1, 0xcb, 0x3c, 0x5f, 0x89, 0x26, 0xce, 0x4b, 0x8e, 0x67, 0x87, 0xb4, 0x1c, 0x42, 0x9a, 0xa8, 0xbf, 0x48, 0xf0, 0xaf, 0x66, 0x40, 0xb4, 0x6, 0x33, 0xce, 0xab, 0x7, 0xf2, 0xbd, 0x68, 0xe6, 0xa7, 0x6c, 0x3c, 0x1d, 0xa7, 0xdb, 0x89, 0xb2, 0xec, 0xda, 0xf6, 0xc, 0xfa, 0x56, 0x7f, 0xe4, 0xd, 0xef, 0xa9, 0xa9, 0x65, 0x29, 0x1b, 0xea, 0x5a, 0xf3, 0xc1, 0x47, 0x58, 0x8b, 0x40, 0x3, 0xe4, 0xe9, 0xf8, 0x44, 0x9a, 0xd, 0x73, 0x4f, 0xeb, 0x4c, 0x85, 0x3e, 0x72, 0x47, 0x19, 0x18, 0xad, 0x9, 0x69, 0xb5, 0xad, 0xf9, 0xad, 0xcd, 0x5b, 0xac, 0x61, 0x35, 0xf6, 0x6c, 0xd9, 0xeb, 0x1d, 0x57, 0x76, 0x93, 0xe7, 0xc2, 0xf8, 0xb4, 0xe3, 0x45, 0xf1, 0x6, 0x9, 0x5c, 0x20, 0x51, 0x8d, 0xb0, 0x4d, 0x19, 0xb4, 0x2b, 0x34, 0x7a, 0xa3, 0x1f, 0xa9, 0xaa, 0x80, 0x1a, 0x95, 0x5e, 0x59, 0xaf, 0x9f, 0xfe, 0x61, 0x43, 0xf0, 0x8e, 0xf3, 0x15, 0x2c, 0xc4, 0x4f, 0x3c, 0x26, 0x7b, 0xeb, 0xf1, 0xd0, 0xf8, 0xf8, 0xda, 0xb0, 0x74, 0x81, 0x42, 0xb0, 0x63, 0x62, 0x64, 0x4d, 0xdb, 0x78, 0x9c, 0xc5, 0xf7, 0xc7, 0x3, 0xdf, 0xb2, 0xa7, 0xaa, 0x1a, 0x1a, 0x18, 0xcf, 0x62, 0x8d, 0x5, 0x79, 0x60, 0x91, 0xe2, 0xf0, 0x7e, 0x18, 0x51, 0xa6, 0xb2, 0xe1, 0x59, 0x55, 0xfd, 0x85, 0x21, 0x8f, 0xbd, 0xd1, 0xbd, 0x8b, 0x8a, 0x5b, 0x57, 0x42, 0x7a, 0x1c, 0x88, 0x54, 0xae, 0x53, 0xf8, 0x7c, 0xb8, 0xda, 0x5b, 0xf9, 0xea, 0x68, 0x27, 0xe, 0x6c, 0x47, 0x79, 0x87, 0xee, 0x79, 0x69, 0x96, 0xa1, 0x99, 0xdc, 0x1d, 0xd9, 0xb5, 0x25, 0xcf, 0x49, 0x7c, 0xb2, 0x5c, 0x34, 0xaf, 0xeb, 0x4b, 0x44, 0x43, 0x28, 0x11, 0x96, 0x96, 0x4b, 0x74, 0xc8, 0x6a, 0xbf, 0x45, 0xb9, 0xb8, 0xa8, 0x19, 0x9d, 0xbf, 0x17, 0xe1, 0x83, 0x2b, 0x80, 0xb9, 0x7c, 0x82, 0x8a, 0xfc, 0x95, 0x45, 0xfd, 0x80, 0xfb, 0x32, 0xe8, 0x39, 0x50, 0x46, 0x2a, 0xb2, 0x17, 0x3e, 0x27, 0xc8, 0xc9, 0xbc, 0x18, 0xa5, 0x18, 0x4, 0x95, 0x96, 0x62, 0xb4, 0x6f, 0xde, 0xec, 0x7a, 0x22, 0x58, 0xb1, 0xe, 0xb9, 0x51, 0xce, 0xa2, 0xe4, 0x24, 0xfe, 0xa6, 0xac, 0xad, 0x26, 0x81, 0x19, 0x7b, 0x8a, 0xb5, 0x92, 0xd1, 0x20, 0x1, 0xce, 0x32, 0x36, 0x7a, 0x1d, 0x5f, 0x6e, 0xcb, 0x68, 0x7e, 0xc2, 0xbb, 0x8c, 0x73, 0x6e, 0xfb, 0x65, 0xc7, 0xd5, 0x4d, 0x4d, 0x16, 0x55, 0x55, 0xaf, 0xb2, 0xa5, 0x16, 0xf6, 0x96, 0x22, 0xb3, 0xd8, 0xd7, 0x54, 0x33, 0xae, 0x40, 0x4, 0xa, 0xbc, 0xcd, 0xd8, 0xe4, 0xec, 0xa8, 0xf7, 0xd3, 0x83, 0xb, 0x8b, 0x44, 0xa, 0x9d, 0xf4, 0xf8, 0x18, 0x84, 0x7e, 0xd1, 0x72, 0x1c, 0xfd, 0x2c, 0xa0, 0x36, 0x1e, 0x51, 0xb9, 0x39, 0xed, 0xf0, 0x4c, 0x4, 0x1b, 0xf5, 0xba, 0x2d, 0x93, 0x17, 0x4d, 0xd8, 0x66, 0x9b, 0x1, 0x71, 0x1c, 0xac, 0x43, 0xd6, 0xf2, 0x5, 0x4, 0xa8, 0x1b, 0x33, 0xea, 0xd7, 0xc1, 0x77, 0x57, 0x8, 0x28, 0xef, 0x69, 0x9b, 0xb6, 0x35, 0x90, 0x8b, 0x1e, 0x90, 0xfc, 0xc5, 0xe2, 0x37, 0xc4, 0xf5, 0x99, 0x66, 0xef, 0x6, 0x86, 0xef, 0x10, 0x41, 0x3, 0xb6, 0x5c, 0x77, 0x28, 0xad, 0xe3, 0x2a, 0xe9, 0x3b, 0x31, 0x69, 0x86, 0xcd, 0x33, 0x79, 0x7, 0x7, 0x5d, 0xbd, 0x6, 0x4a, 0x57, 0x5b, 0x4e, 0x4e, 0xc4, 0x16, 0x99, 0x6d, 0x6a, 0x19, 0x47, 0xfa, 0xfd, 0xe8, 0xe5, 0xe2, 0xee, 0xea, 0xc6, 0xdc, 0xc7, 0xf6, 0xca, 0x6c, 0x52, 0xce, 0xed, 0xc6, 0xc9, 0xec, 0x9e, 0xc5, 0xe3, 0xd0, 0x2f, 0x6d, 0x4c, 0xd2, 0x5a, 0xa2, 0xd2, 0x47, 0x3a, 0xe0, 0x88, 0x15, 0x39, 0x4b, 0xaa, 0x5b, 0xae, 0x9e, 0xe0, 0xd2, 0xce, 0x8a, 0x25, 0xd, 0x91, 0xac, 0x26, 0xf4, 0x35, 0x34, 0xa2, 0x44, 0xef, 0xf8, 0x29, 0x2b, 0x37, 0x7a, 0x5a, 0xc1, 0x55, 0xdd, 0xea, 0x86, 0xc4, 0x3e, 0x53, 0x41, 0x67, 0xb8, 0xf5, 0x91, 0x7c, 0xa6, 0x22, 0xfc, 0xa4, 0xa2, 0xf0, 0x7e, 0xce, 0xc, 0xec, 0x7, 0x6, 0x7c, 0x74, 0x20, 0xd, 0xb2, 0x96, 0x20, 0xfd, 0xb2, 0x46, 0x36, 0x0, 0x6d, 0xad, 0x9b, 0xff, 0x3d, 0xc8, 0xc, 0x44, 0x2d, 0x6f, 0xb7, 0xec, 0x13, 0x2d, 0x4, 0xa, 0x35, 0x20, 0x8b, 0x33, 0x6a, 0x8a, 0x2b, 0x1c, 0x0, 0x2e, 0xa5, 0x24, 0xbe, 0x38, 0x9f, 0x93, 0xd4, 0xc8, 0x4b, 0x5c, 0xe9, 0x93, 0xa3, 0x9b, 0x21, 0xa, 0xaa, 0x5c, 0x9f, 0x2f, 0xb3, 0x57, 0x74, 0x6d, 0xac, 0xb9, 0xb9, 0xfa, 0x7b, 0xb1, 0x7c, 0x39, 0x6b, 0x18, 0xbd, 0x30, 0x30, 0xd9, 0xb0, 0x28, 0xe5, 0xd3, 0xab, 0x6d, 0x23, 0x1a, 0xb5, 0xad, 0x4b, 0xea, 0x2b, 0x3c, 0x4a, 0xfa, 0x9c, 0xc5, 0xa3, 0xf8, 0xbb, 0x9a, 0x28, 0x6e, 0xb1, 0xa9, 0x1d, 0x19, 0x44, 0xd9, 0xd0, 0xe9, 0x80, 0xb9, 0x87, 0xe5, 0xe3, 0x85, 0x80, 0xb2, 0x43, 0xb4, 0x9f, 0x11, 0x55, 0xc9, 0x5f, 0xbd, 0x80, 0x9c, 0x74, 0x28, 0x28, 0x20, 0x3c, 0x8d, 0x73, 0x1d, 0x78, 0x4b, 0x45, 0xc7, 0x73, 0x68, 0x89, 0xd, 0x2a, 0xa4, 0x48, 0xbe, 0x65, 0x90, 0x9b, 0xcf, 0xbc, 0x3, 0x3b, 0x8c, 0x52, 0xf8, 0x57, 0x5d, 0xce, 0xdb, 0x1c, 0x8, 0xe3, 0x5e, 0xee, 0x94, 0xab, 0xdb, 0x90, 0xff, 0xde, 0xe3, 0x68, 0xdc, 0xb2, 0x64, 0xec, 0x55, 0x39, 0x67, 0x6b, 0xd7, 0x8d, 0x0, 0xc7, 0x6e, 0x29, 0x93, 0x84, 0x5b, 0x95, 0x7c, 0x1d, 0x21, 0x6c, 0x2d, 0x36, 0xbd, 0x80, 0xe4, 0x4f, 0x19, 0x5f, 0x8, 0xb0, 0x4d, 0x3e, 0x50, 0x95, 0x38, 0x36, 0xd7, 0x80, 0x12, 0x85, 0x5c, 0x1d, 0x43, 0x5e, 0x47, 0x26, 0x1a, 0x68, 0xd, 0xcd, 0xe6, 0xaa, 0x6a, 0x9b, 0x9c, 0xcf, 0x3, 0xb9, 0xea, 0xbe, 0x69, 0x44, 0xf2, 0x95, 0xf5, 0x29, 0x83, 0x87, 0x77, 0x55, 0x8b, 0xc7, 0x8, 0x70, 0x14, 0xc6, 0x4d, 0x8f, 0xab, 0xc, 0x42, 0x39, 0xbc, 0x1b, 0x9b, 0xf5, 0x7c, 0xf, 0x78, 0x63, 0x52, 0x6c, 0x21, 0x45, 0x7f, 0x1, 0xfe, 0x10, 0x1f, 0x4d, 0x64, 0x6f, 0x7a, 0xcb, 0x9f, 0x71, 0xf2, 0x7c, 0xc6, 0xc0, 0x6, 0xaa, 0xfb, 0x91, 0xa3, 0xd3, 0x10, 0x38, 0xc4, 0x9f, 0x5f, 0x28, 0x32, 0xe4, 0xe2, 0x5c, 0x47, 0x80, 0x53, 0x6f, 0x89, 0xb9, 0x32, 0x8, 0xd3, 0x4d, 0x5, 0x82, 0x7c, 0x1b, 0x50, 0x92, 0x9d, 0xb1, 0xd1, 0xc, 0xd8, 0x5e, 0x8, 0xe9, 0xe7, 0x6b, 0x9b, 0xec, 0xd2, 0x86, 0xf, 0xe4, 0xe0, 0xf9, 0x51, 0x35, 0xd6, 0xaa, 0xda, 0x46, 0x63, 0x5e, 0x77, 0xa3, 0x2c, 0x22, 0x76, 0x81, 0x4b, 0xbf, 0x8e, 0xa5, 0x66, 0x1, 0xb9, 0xd4, 0xd4, 0x1c, 0xf3, 0x8c, 0x61, 0x5d, 0xcb, 0xb5, 0x5, 0x57, 0x4b, 0xd, 0xb, 0x6a, 0xba, 0xfd, 0x8c, 0xe4, 0xf2, 0x88, 0x9a, 0xc5, 0xc, 0x4e, 0x42, 0x83, 0xa7, 0xc1, 0xfc, 0xc8, 0x69, 0xa9, 0x94, 0xa4, 0x51, 0xc8, 0xb7, 0x72, 0xc5, 0x4b, 0x16, 0x9, 0x4b, 0xcb, 0xe5, 0x1b, 0xe9, 0xdf, 0xa3, 0x2c, 0xd3, 0x46, 0xb4, 0xac, 0xbd, 0x2c, 0x4d, 0x5, 0xa8, 0x84, 0x46, 0x2e, 0x4d, 0xa3, 0x1a, 0xeb, 0xce, 0x47, 0x3c, 0xe7, 0x94, 0xb5, 0xae, 0x1e, 0xe3, 0x5d, 0xee, 0x79, 0x6f, 0xae, 0xfd, 0x3f, 0xa9, 0xf6, 0xf1, 0x85, 0xce, 0x7, 0x20, 0x5, 0xe1, 0xed, 0x77, 0x37, 0x42, 0xbf, 0xda, 0xc7, 0x66, 0xf8, 0xe4, 0xb9, 0xc7, 0x7d, 0x47, 0xad, 0xf7, 0x2d, 0xe, 0x9e, 0xc3, 0xa8, 0xd0, 0x11, 0x9, 0x6a, 0x77, 0x4b, 0x0, 0x34, 0xb0, 0x19, 0x53, 0x62, 0xc6, 0x41, 0x76, 0x51, 0xa8, 0x14, 0xd8, 0x20, 0xcf, 0x86, 0x47, 0xc3, 0xfd, 0x5c, 0xa1, 0x1e, 0xba, 0x81, 0x48, 0xa8, 0x9b, 0xe8, 0x67, 0x60, 0x48, 0xed, 0x95, 0x51, 0x59, 0xe6, 0xf5, 0x79, 0xe0, 0x70, 0xae, 0x93, 0x88, 0x1e, 0xf9, 0xbb, 0xfe, 0x5d, 0x68, 0x4f, 0xbf, 0xbd, 0xf0, 0x85, 0xa9, 0x45, 0xf8, 0xd6, 0x63, 0x7c, 0x1f, 0xaa, 0xdf, 0x65, 0xdd, 0x93, 0xf, 0x12, 0xe, 0xcb, 0x48, 0x40, 0xd6, 0x8f, 0x6f, 0xa2, 0x6c, 0x9c, 0xce, 0xd7, 0x7f, 0xa, 0xb4, 0x3f, 0x97, 0x26, 0xaf, 0x80, 0x1f, 0x1c, 0x81, 0xed, 0x6e, 0xf1, 0x4, 0x39, 0x96, 0x3f, 0xfd, 0xf8, 0x9f, 0x5a, 0x8d, 0xf5, 0x72, 0x38, 0x17, 0x11, 0x1, 0x9e, 0x3e, 0xb8, 0xfa, 0xac, 0x62, 0xb, 0x2e, 0x95, 0x77, 0xae, 0xef, 0x48, 0x2d, 0x92, 0xc0, 0x6a, 0x4e, 0x67, 0x86, 0xba, 0x96, 0x82, 0x27, 0xb8, 0x18, 0x81, 0x45, 0x37, 0xab, 0x9c, 0xe6, 0xf2, 0xab, 0xb7, 0xb8, 0x9c, 0x34, 0xcf, 0xe, 0xa3, 0x44, 0x76, 0x24, 0x76, 0xd2, 0x8b, 0xe9, 0x27, 0x22, 0xea, 0x1e, 0xf9, 0xb, 0x6b, 0xb7, 0x1, 0xbf, 0x4c, 0x33, 0xf2, 0xd3, 0xd0, 0x4b, 0x47, 0xf3, 0x3b, 0x2f, 0x7f, 0xa5, 0x8, 0x38, 0xfb, 0x59, 0xd7, 0xc4, 0xde, 0x71, 0x26, 0x58, 0xbc, 0xe7, 0x8, 0xac, 0x4b, 0xcc, 0x33, 0x72, 0x7c, 0xb0, 0xb4, 0xe, 0x82, 0xca, 0x4b, 0xc, 0x6a, 0x2f, 0xcf, 0xde, 0xb0, 0x7f, 0x17, 0xb2, 0xf4, 0xc9, 0x77, 0xd4, 0x59, 0x7e, 0xb1, 0x60, 0xb3, 0x61, 0xd4, 0x80, 0xd3, 0x20, 0xe4, 0xec, 0xa5, 0x93, 0x21, 0x8b, 0x48, 0x54, 0xac, 0xab, 0xa6, 0xeb, 0xe8, 0xa4, 0xf4, 0x3a, 0x9b, 0x75, 0x36, 0xd4, 0x42, 0x92, 0xca, 0x4b, 0x4e, 0x4c, 0x5f, 0x1f, 0x2d, 0xab, 0x1e, 0xff, 0xe0, 0x11, 0x4f, 0x7d, 0xab, 0x9c, 0xc0, 0xe2, 0xdd, 0xf9, 0xbd, 0xa2, 0x81, 0xa6, 0xf8, 0x1a, 0x15, 0xd2, 0xd4, 0x20, 0x83, 0xc6, 0x30, 0x32, 0x51, 0xe5, 0xaf, 0xe2, 0x7a, 0x5c, 0x6, 0x3f, 0x7d, 0xcc, 0x18, 0xa1, 0xbe, 0xff, 0xb8, 0xa5, 0x12, 0xeb, 0x5c, 0xf3, 0x25, 0x8e, 0xc6, 0x65, 0x77, 0x19, 0x25, 0x65, 0x74, 0xa8, 0xe5, 0xd6, 0x99, 0x91, 0x43, 0xf2, 0xcb, 0x66, 0x7f, 0x2, 0x36, 0x4b, 0x5c, 0x92, 0x44, 0xe5, 0x17, 0x98, 0x7a, 0x30, 0xfe, 0x39, 0x52, 0xcd, 0x98, 0x1e, 0xb1, 0x4d, 0xd5, 0x28, 0x5, 0x6b, 0x7b, 0x65, 0xaf, 0x18, 0xd2, 0x10, 0x84, 0x30, 0xbe, 0xe0, 0x19, 0x75, 0xe2, 0x67, 0x62, 0x9b, 0xeb, 0x81, 0x86, 0xc7, 0x18, 0x55, 0xea, 0x54, 0x6e, 0x4d, 0x63, 0xf4, 0xf, 0x5a, 0x29, 0x88, 0x54, 0x1d, 0xa5, 0xa3, 0xed, 0x98, 0x2c, 0x66, 0xeb, 0x63, 0xc3, 0x58, 0x60, 0xad, 0xf1, 0xf5, 0x22, 0x4a, 0x57, 0x8d, 0x4b, 0x7b, 0xfe, 0x3e, 0xfb, 0xa, 0xf1, 0xaa, 0xf8, 0xd2, 0x12, 0xd8, 0x57, 0xbd, 0x2a, 0x8, 0xfa, 0x8c, 0xaf, 0xd, 0xe7, 0x55, 0x8d, 0x7a, 0xe2, 0x6c, 0x6f, 0x49, 0xa9, 0x6a, 0xb6, 0xbf, 0xac, 0x9d, 0x7f, 0xb3, 0x8b, 0xfd, 0xbb, 0xa8, 0xe2, 0x96, 0x51, 0x7c, 0xe, 0x39, 0x76, 0xe2, 0x2f, 0x20, 0x6, 0xc5, 0x8f, 0x12, 0x19, 0x21, 0xed, 0xc8, 0x2a, 0xe5, 0x79, 0xe5, 0x27, 0x1c, 0x8c, 0xbd, 0xfc, 0x90, 0xe8, 0xc4, 0x80, 0x42, 0xf8, 0x8, 0xde, 0xe9, 0x5a, 0x58, 0x9c, 0x8c, 0xbe, 0x1, 0x57, 0x74, 0x52, 0xa2, 0x2f, 0x8a, 0xd1, 0xb6, 0xb, 0x26, 0x62, 0xe1, 0x5f, 0x8c, 0x2d, 0xc9, 0x47, 0xd7, 0x94, 0x66, 0x88, 0x97, 0xeb, 0x5b, 0x9e, 0x91, 0x6f, 0xc4, 0x29, 0x38, 0x63, 0xb0, 0xf7, 0xc3, 0xf0, 0x79, 0x22, 0x3b, 0xa7, 0x87, 0xd7, 0x13, 0x1, 0x5, 0xbe, 0x4f, 0x3f, 0x1b, 0xd3, 0xd8, 0x2f, 0x6b, 0x6d, 0xb1, 0x72, 0x22, 0xda, 0x2f, 0x95, 0xcc, 0x51, 0xe8, 0xde, 0xb1, 0x1a, 0xbb, 0x80, 0x9f, 0x86, 0x7b, 0x5f, 0x7, 0x85, 0x28, 0xee, 0x8a, 0x3c, 0xc4, 0x2f, 0x57, 0xdb, 0xc2, 0xa8, 0xc7, 0x49, 0xf8, 0xc7, 0x33, 0x37, 0xa3, 0xc7, 0x40, 0x2f, 0xb2, 0x78, 0xe6, 0x89, 0xa, 0xfe, 0xd5, 0x27, 0x7d, 0xca, 0x1d, 0xa0, 0xf1, 0x94, 0x7b, 0x7d, 0x94, 0x8, 0xba, 0x94, 0x9, 0x76, 0xde, 0x3d, 0xd7, 0x29, 0x91, 0x61, 0x8a, 0x71, 0x22, 0x6f, 0x8b, 0xb5, 0x1a, 0xb4, 0xbf, 0xb9, 0xbd, 0xe1, 0x9b, 0xa3, 0x5b, 0x65, 0xf2, 0xd5, 0xf8, 0xf8, 0x13, 0xf0, 0xf5, 0xf1, 0x68, 0xe4, 0x1b, 0x55, 0x76, 0xb9, 0x2f, 0xd0, 0x71, 0xc5, 0xcd, 0x74, 0x71, 0x38, 0x18, 0x67, 0x55, 0x2d, 0x67, 0x1b, 0x60, 0xae, 0x17, 0xda, 0x4d, 0x77, 0xb0, 0x6a, 0xdb, 0xd4, 0xf2, 0x98, 0x9d, 0x79, 0x9f, 0x39, 0x37, 0x76, 0xd8, 0xfb, 0x8a, 0x1, 0x16, 0xa3, 0x3a, 0x73, 0xa, 0xea, 0x42, 0xe6, 0xf4, 0x28, 0x4d, 0x68, 0x35, 0x5b, 0xb9, 0x93, 0x1c, 0xd7, 0xad, 0x3c, 0x45, 0xbf, 0x5d, 0xf1, 0x75, 0x55, 0x6a, 0xa3, 0x31, 0xd7, 0xd0, 0x92, 0x98, 0x10, 0x59, 0xb8, 0x3a, 0x17, 0xd3, 0x4e, 0xdd, 0xe9, 0xdd, 0x71, 0x3c, 0xcf, 0xbb, 0x6d, 0xce, 0x3b, 0x96, 0xde, 0xd1, 0x8d, 0xc5, 0x72, 0x7a, 0xd6, 0xd9, 0x2b, 0xb8, 0x17, 0x63, 0xa0, 0xc, 0xc, 0x30, 0xdd, 0x32, 0x90, 0xd3, 0xea, 0x65, 0xcb, 0x3d, 0x69, 0x3b, 0xb, 0x38, 0xc1, 0xf5, 0xbf, 0x74, 0x66, 0x57, 0xd7, 0xda, 0xac, 0xe1, 0xe0, 0xed, 0xc2, 0xad, 0xbe, 0x49, 0x93, 0xd6, 0xfd, 0xb1, 0x50, 0xd4, 0x91, 0x69, 0xf0, 0x64, 0x9f, 0xf9, 0x6b, 0x3e, 0x25, 0xae, 0xe1, 0x12, 0xe3, 0x8e, 0xf3, 0xac, 0xf4, 0x3c, 0x5e, 0xb7, 0x8d, 0xad, 0xb5, 0xcd, 0x7b, 0xf2, 0x96, 0x9, 0x93, 0x98, 0xd, 0x53, 0x15, 0xee, 0x2f, 0xc0, 0x3c, 0x4c, 0xf1, 0xcb, 0x4c, 0xd5, 0x15, 0x7b, 0x68, 0x6, 0x90, 0x85, 0x2a, 0x37, 0xa7, 0x2f, 0xdf, 0x76, 0xaf, 0x5, 0x2f, 0xca, 0x1b, 0x4e, 0x9e, 0xd3, 0xeb, 0xe0, 0x77, 0xdf, 0x66, 0x76, 0x37, 0x36, 0x57, 0xcf, 0x22, 0xc5, 0x21, 0x86, 0xd1, 0x48, 0xc0, 0xb4, 0xf6, 0xf0, 0x37, 0xb6, 0x90, 0x1c, 0xc5, 0xdd, 0x6e, 0x65, 0xfc, 0x64, 0x73, 0x47, 0x0, 0x4d, 0xe5, 0xda, 0x88, 0x95, 0xed, 0xa2, 0xf2, 0x6d, 0xd, 0x3e, 0xff, 0xa1, 0xbb, 0xfe, 0x64, 0xdb, 0x4, 0xb5, 0x79, 0x60, 0x91, 0xd1, 0x70, 0x14, 0xa7, 0x26, 0xa, 0xfb, 0xbd, 0x1c, 0x34, 0x91, 0xf0, 0x7b, 0xba, 0x7f, 0x58, 0xa3, 0xa0, 0x32, 0x65, 0x3e, 0x81, 0x37, 0x25, 0x77, 0xba, 0x63, 0xc2, 0x36, 0xf5, 0xd4, 0xe8, 0x71, 0xc7, 0x1d, 0xe4, 0xba, 0x79, 0x1a, 0x37, 0x46, 0xfe, 0xfd, 0xcc, 0x64, 0x60, 0xa9, 0xe1, 0x25, 0x74, 0xd5, 0xb0, 0x9d, 0x73, 0x58, 0x6c, 0xf5, 0xf9, 0xeb, 0xb8, 0x89, 0x3e, 0xf3, 0x77, 0xc9, 0x76, 0x8b, 0x31, 0xf6, 0xdb, 0xe1, 0x98, 0x57, 0x3f, 0x18, 0x5c, 0xa3, 0xcb, 0xb2, 0xa6, 0x26, 0x7c, 0xb3, 0xa8, 0xa3, 0x68, 0x1c, 0x56, 0x25, 0xed, 0x44, 0xa5, 0x4c, 0x9e, 0x49, 0xc0, 0xdd, 0xdb, 0x9f, 0x22, 0xdb, 0x27, 0x64, 0xe0, 0x67, 0x85, 0xd7, 0x97, 0xfc, 0xd2, 0xfd, 0x5f, 0xdb, 0x4d, 0x21, 0xba, 0x17, 0x9e, 0x53, 0xe3, 0x5d, 0xdd, 0x5, 0x8c, 0xfc, 0x14, 0x91, 0xe2, 0x9a, 0x7e, 0xe, 0x46, 0x86, 0x96, 0x2d, 0x94, 0x6b, 0xf7, 0x46, 0xed, 0x29, 0x8e, 0x84, 0xf0, 0xf4, 0x4d, 0x5a, 0x34, 0x93, 0x8d, 0x1, 0x3a, 0x1b, 0x8e, 0xaf, 0x83, 0x92, 0x90, 0x1f, 0xef, 0x61, 0x6e, 0x61, 0xbf, 0xd7, 0x59, 0xab, 0xdf, 0x36, 0xf2, 0x55, 0x63, 0xeb, 0x1a, 0x62, 0x1a, 0xd6, 0x31, 0x3e, 0xd5, 0xfb, 0xdd, 0x8d, 0x39, 0x63, 0x7a, 0xaa, 0x9a, 0xfb, 0xd6, 0xf2, 0x5c, 0x3a, 0x90, 0xd1, 0x48, 0x57, 0xa9, 0x3c, 0xae, 0xd0, 0x65, 0x9e, 0xc9, 0xad, 0xfa, 0x7a, 0xa9, 0x4d, 0xba, 0xf7, 0xd4, 0x23, 0xc4, 0x54, 0xc3, 0x56, 0x58, 0xf3, 0x2c, 0xd6, 0x3a, 0x13, 0x14, 0x74, 0x9f, 0xb8, 0xda, 0x7a, 0x8c, 0xa0, 0xad, 0x5e, 0xf7, 0xfe, 0xad, 0x23, 0x5d, 0x3b, 0x65, 0xed, 0xa5, 0x74, 0xc8, 0x2e, 0x4b, 0xcb, 0x75, 0x24, 0xbf, 0x27, 0x5e, 0x3c, 0x8a, 0x9b, 0x32, 0x45, 0x41, 0x4f, 0xa3, 0x73, 0x7a, 0x16, 0x6, 0x8d, 0x16, 0x9f, 0x6f, 0xcc, 0xe8, 0x37, 0xa7, 0x6c, 0xc5, 0x30, 0x5f, 0xd5, 0x39, 0x89, 0xbe, 0x32, 0x6b, 0x98, 0x9b, 0x98, 0xbd, 0xf9, 0xff, 0x59, 0x3c, 0xdb, 0x90, 0x18, 0x5d, 0x3c, 0xc7, 0xe7, 0xfd, 0xee, 0x9a, 0x4, 0x93, 0xca, 0x7d, 0xe6, 0xde, 0x68, 0xe1, 0x30, 0x2, 0xb4, 0x13, 0x6a, 0x17, 0x6d, 0x9, 0x3a, 0xea, 0x3e, 0xea, 0x18, 0x5d, 0x63, 0x18, 0x8d, 0x1b, 0xbd, 0x38, 0xe0, 0xcd, 0xa1, 0xd7, 0x11, 0xd2, 0xac, 0xe2, 0xe8, 0x6b, 0x37, 0x35, 0xba, 0x5f, 0x66, 0xae, 0xdb, 0x2b, 0x5f, 0x98, 0x6c, 0x5a, 0x3e, 0xaf, 0x9c, 0xf7, 0x7d, 0x41, 0xb4, 0x60, 0xc, 0xcd, 0xa, 0xe1, 0xb0, 0xf9, 0xf1, 0xf8, 0xf6, 0xf4, 0xfb, 0xb2, 0xe6, 0xa3, 0x8a, 0x6e, 0x88, 0xe3, 0xf2, 0x38, 0xf8, 0x45, 0xf9, 0xc5, 0xa1, 0x38, 0xb4, 0x79, 0x2, 0x6e, 0xb2, 0x8f, 0xfd, 0x5, 0xd7, 0xd8, 0x36, 0xc6, 0xbc, 0x82, 0x4e, 0xd3, 0xfc, 0x34, 0xe5, 0x2c, 0x98, 0x40, 0x7f, 0xc2, 0xba, 0xea, 0x70, 0x6a, 0x35, 0x51, 0xa2, 0x6b, 0x48, 0x8e, 0xb8, 0x25, 0x9d, 0x9e, 0x9e, 0x5d, 0xfd, 0xa7, 0xb1, 0x27, 0x6f, 0xbe, 0x50, 0x1c, 0x89, 0x50, 0x90, 0xa4, 0x6d, 0x1a, 0x81, 0xbd, 0x27, 0xce, 0xbe, 0xd9, 0x7, 0x20, 0xdd, 0x9f, 0x25, 0xb6, 0x60, 0x18, 0x4d, 0x57, 0xa, 0xb2, 0x9c, 0x79, 0x3b, 0xb2, 0x97, 0xd1, 0x97, 0xdf, 0xef, 0x4d, 0x7f, 0xcb, 0xbe, 0xd7, 0x40, 0x19, 0xed, 0x3e, 0x46, 0x17, 0x7a, 0x7c, 0xac, 0x9e, 0x31, 0xfb, 0x2d, 0x18, 0x49, 0x53, 0xe1, 0xa2, 0x2f, 0x15, 0xe1, 0xa5, 0x9d, 0xf9, 0xb5, 0x77, 0x94, 0x77, 0xe4, 0x33, 0x63, 0x74, 0x1b, 0x57, 0x61, 0x8c, 0x1c, 0xad, 0x14, 0x47, 0xdd, 0xc5, 0xe3, 0x2f, 0xb7, 0x55, 0x6, 0x91, 0x37, 0x53, 0xe9, 0xa6, 0xcc, 0x55, 0x98, 0x5, 0x44, 0xf8, 0x75, 0xf9, 0x9, 0xd0, 0x7c, 0xd9, 0xed, 0xd0, 0x1a, 0x3e, 0xd2, 0x53, 0xb7, 0x97, 0xe8, 0xb0, 0x64, 0xe9, 0xae, 0x2b, 0xf, 0x26, 0x6c, 0x92, 0x6e, 0x60, 0x7c, 0x73, 0xe3, 0x38, 0xca, 0xa9, 0xfd, 0x43, 0x3a, 0x4e, 0xb9, 0x43, 0x42, 0x74, 0xc8, 0xeb, 0x68, 0xfd, 0x79, 0x4a, 0xed, 0xce, 0x79, 0xb5, 0xc7, 0x24, 0x26, 0xf1, 0xad, 0x56, 0xb5, 0x74, 0x62, 0x8f, 0xb4, 0x43, 0xab, 0x9a, 0xbb, 0x9, 0x37, 0x98, 0x10, 0x4e, 0xfb, 0x1, 0x2b, 0xbd, 0xeb, 0xfa, 0x85, 0x86, 0x9c, 0x6d, 0xc2, 0xe0, 0x7a, 0xe8, 0x23, 0xac, 0xce, 0x7, 0x71, 0xaf, 0x7a, 0x35, 0xe5, 0xed, 0xf1, 0x40, 0x78, 0x6, 0xde, 0xd, 0xc8, 0x92, 0x8b, 0x1f, 0x7f, 0x25, 0x88, 0x38, 0x56, 0xe7, 0xb0, 0xf3, 0xfe, 0x6c, 0xa5, 0x21, 0x3e, 0x24, 0x52, 0x61, 0xa2, 0x38, 0xc6, 0x54, 0x70, 0xd8, 0x16, 0xbb, 0x5e, 0x3d, 0x8a, 0xe9, 0x22, 0x2f, 0x7e, 0xb4, 0xbe, 0x68, 0x58, 0xae, 0xc1, 0x5a, 0xd5, 0xf1, 0x51, 0xaa, 0x1d, 0x9e, 0xe9, 0x3d, 0x57, 0xa2, 0xc9, 0xe4, 0x5b, 0x46, 0x1d, 0x84, 0x30, 0x99, 0xd7, 0x9e, 0x52, 0x77, 0x64, 0x70, 0x77, 0xbd, 0x86, 0x9e, 0xe8, 0x4a, 0xe7, 0x1c, 0xc2, 0x3e, 0x2e, 0x30, 0xd0, 0xc6, 0x7e, 0xa, 0x41, 0xdd, 0x48, 0xb2, 0xea, 0x83, 0x72, 0x3d, 0x3b, 0x3, 0x37, 0xb6, 0xc9, 0x9f, 0xa8, 0xce, 0x37, 0x26, 0xd6, 0xbf, 0x9a, 0x19, 0xfc, 0x8a, 0x1f, 0x79, 0xcf, 0xc5, 0xfb, 0x34, 0xa7, 0xc5, 0x7a, 0x53, 0x6f, 0xb8, 0xeb, 0xbe, 0x59, 0xf6, 0x17, 0x90, 0xb0, 0xf5, 0x6c, 0xa4, 0x87, 0x20, 0x8d, 0xdf, 0x19, 0xfe, 0x12, 0x9b, 0x77, 0x1f, 0xf7, 0x46, 0xb0, 0xf8, 0x6b, 0x75, 0x7, 0x5, 0xa3, 0x81, 0xaa, 0xc2, 0xf7, 0x89, 0x61, 0x7a, 0x66, 0xd1, 0x82, 0x57, 0x3f, 0xed, 0xa3, 0x5a, 0x94, 0x62, 0xd, 0xc8, 0xc9, 0x49, 0x19, 0x5, 0x7c, 0x69, 0xee, 0x13, 0x7b, 0xbb, 0xd0, 0xb4, 0xd4, 0xf5, 0x2d, 0x8e, 0x87, 0xe0, 0x60, 0x61, 0xc9, 0x35, 0x63, 0x75, 0xff, 0xa1, 0xd5, 0x4c, 0x27, 0xd9, 0x9e, 0xbc, 0x51, 0xea, 0x53, 0x7d, 0x93, 0xc, 0x42, 0xd4, 0x6c, 0x65, 0xa6, 0xf6, 0xf5, 0xdd, 0x2b, 0xba, 0xdb, 0xbd, 0x83, 0x8b, 0xa3, 0xb, 0xe3, 0xb3, 0x1, 0xf8, 0x73, 0xab, 0x4, 0x57, 0xe, 0xa0, 0x6, 0x22, 0x64, 0xef, 0x3f, 0xda, 0x48, 0x8, 0x2b, 0x4b, 0x66, 0xa6, 0xc7, 0x7e, 0x2, 0x9c, 0x20, 0x59, 0x78, 0x2e, 0x93, 0x11, 0x71, 0x5a, 0xb4, 0x4c, 0xf0, 0xf1, 0x9d, 0x7b, 0x51, 0x5a, 0x5f, 0x4d, 0x61, 0x71, 0x66, 0xd1, 0xcc, 0xd9, 0x30, 0x8f, 0x71, 0x88, 0xbb, 0x79, 0x83, 0x74, 0x88, 0x27, 0xf4, 0x7f, 0x55, 0x57, 0x27, 0xa0, 0x1c, 0xaa, 0x97, 0x16, 0xe8, 0xbd, 0xed, 0x2b, 0x52, 0x85, 0xf, 0x7c, 0x16, 0x44, 0x3c, 0x12, 0xf9, 0x40, 0x15, 0x36, 0x84, 0x35, 0xf4, 0x3c, 0x61, 0xac, 0xc3, 0x5a, 0xc3, 0x52, 0x9e, 0x89, 0xe0, 0x28, 0xf8, 0x5e, 0x21, 0x52, 0x88, 0xa, 0xa0, 0x56, 0xed, 0xce, 0x21, 0x63, 0x82, 0x80, 0x11, 0x51, 0x1c, 0xe2, 0x94, 0x90, 0x89, 0xa9, 0xd9, 0xd1, 0xc8, 0xfb, 0x52, 0x3c, 0x67, 0x39, 0x3a, 0xc8, 0x7e, 0xdf, 0xf0, 0x45, 0xaa, 0x11, 0xbd, 0x79, 0x79, 0xe, 0xc5, 0xc4, 0x48, 0xeb, 0xb, 0xfb, 0x67, 0xc6, 0x6a, 0x7d, 0xf1, 0x82, 0x2c, 0xaf, 0x16, 0x3e, 0xaa, 0x8b, 0x8f, 0xf7, 0x62, 0x7e, 0xa8, 0x4c, 0xf1, 0x7b, 0xc2, 0x31, 0xfd, 0x1, 0x33, 0x8b, 0xd0, 0xd5, 0x82, 0xe2, 0x3a, 0xb, 0x8d, 0xb2, 0xd3, 0xe6, 0x6a, 0x1e, 0x8d, 0xd6, 0xcb, 0xcb, 0xbb, 0xb9, 0xfc, 0xee, 0x97, 0x9d, 0xcb, 0xc6, 0x9f, 0x2e, 0xb6, 0x12, 0x70, 0xa2, 0x51, 0x4f, 0x9b, 0x2f, 0x79, 0x5f, 0x6c, 0x93, 0xa4, 0xcd, 0x9d, 0x25, 0x65, 0xb7, 0xf7, 0xe2, 0x3e, 0x99, 0x58, 0x2b, 0x86, 0x55, 0x39, 0x56, 0xd5, 0x57, 0x27, 0x54, 0x4a, 0x55, 0x89, 0xb6, 0x2e, 0x2f, 0x7b, 0x5e, 0x98, 0xd7, 0x7f, 0x58, 0xde, 0xcd, 0xbc, 0x76, 0x12, 0xb2, 0x97, 0x63, 0x73, 0x56, 0x97, 0x23, 0xea, 0x76, 0x81, 0xa, 0x5f, 0x54, 0xc1, 0xb1, 0xac, 0x51, 0xbe, 0x63, 0x4c, 0x49, 0x99, 0x25, 0xc7, 0xf5, 0x1a, 0xcf, 0xac, 0x58, 0xf8, 0xa5, 0xc1, 0x60, 0x3e, 0x9b, 0x5, 0x42, 0x9c, 0x7b, 0xdc, 0x79, 0xc6, 0x2f, 0xfe, 0xae, 0x2d, 0x26, 0x73, 0x60, 0x1b, 0x34, 0x1c, 0x34, 0x8e, 0xd8, 0x9a, 0x1f, 0xa, 0x10, 0x7f, 0xe1, 0x44, 0x43, 0x1e, 0x9f, 0x74, 0x3f, 0x59, 0x27, 0xd4, 0x7e, 0x7b, 0xfc, 0x28, 0x97, 0x80, 0xe9, 0xa, 0xf2, 0xd, 0x9b, 0x2d, 0xfd, 0xf0, 0xb, 0x72, 0xcc, 0xbd, 0xe7, 0x59, 0x33, 0x30, 0xf9, 0xfd, 0x84, 0xe1, 0xfb, 0xbd, 0xc1, 0xf7, 0xfb, 0x5, 0x9c, 0x27, 0xf1, 0xf, 0x9b, 0xa5, 0x7d, 0x59, 0x41, 0x43, 0x6d, 0xd4, 0x8f, 0xfc, 0x1f, 0xb0, 0x70, 0x8e, 0xac, 0xfe, 0x2, 0x66, 0x70, 0x7e, 0x7e, 0x78, 0x83, 0x6, 0x51, 0x85, 0xa2, 0xce, 0xf9, 0x5, 0x1, 0x65, 0x8e, 0xa9, 0x3f, 0xc0, 0xde, 0xc7, 0xf3, 0xfd, 0x69, 0x9b, 0xa2, 0x1e, 0xb7, 0xc, 0x6a, 0xa3, 0x1e, 0xfa, 0x97, 0x98, 0x58, 0x2c, 0x7f, 0xf8, 0xfe, 0x1d, 0x2, 0xa8, 0x2, 0xff, 0x53, 0x28, 0x44, 0x44, 0x42, 0x41, 0x45, 0x41, 0x41, 0x80, 0x43, 0xfb, 0x4f, 0x9, 0xa, 0x0, 0x8f, 0x4b, 0xcb, 0x83, 0x80, 0x27, 0xa5, 0x49, 0xc7, 0x2b, 0xad, 0x65, 0xe, 0xc4, 0xb7, 0x80, 0xb8, 0x87, 0xa4, 0x20, 0xd2, 0xd0, 0x83, 0xf8, 0x8a, 0x9b, 0x6e, 0x43, 0x53, 0x4b, 0x9a, 0xfb, 0xe7, 0xf7, 0x24, 0x65, 0xb4, 0x2d, 0x7, 0x16, 0xee, 0x3c, 0xd2, 0xf6, 0xc3, 0x8, 0x18, 0x34, 0x74, 0x3c, 0x4b, 0x7, 0x87, 0x16, 0xff, 0xa7, 0x42, 0x85, 0xf6, 0xfe, 0x9f, 0x9, 0xbe, 0x95, 0xa4, 0x1, 0x4a, 0x1, 0xa2, 0xb2, 0x5d, 0xd6, 0xda, 0x5c, 0x7c, 0xf6, 0xd6, 0x35, 0x5a, 0x1a, 0xfb, 0x87, 0xa4, 0x66, 0x2e, 0x32, 0xe, 0x97, 0xe3, 0xc4, 0xfb, 0x70, 0x25, 0x76, 0xd5, 0xc, 0x43, 0x2d, 0x8b, 0x81, 0x68, 0x22, 0xf6, 0xc0, 0x5a, 0x3, 0xb2, 0x75, 0xf2, 0x92, 0xc0, 0xc3, 0x39, 0xe6, 0x92, 0x39, 0xc6, 0x1, 0x49, 0x26, 0x7e, 0x4, 0x2d, 0x32, 0xf6, 0x68, 0x6, 0xc4, 0x2d, 0x62, 0xb4, 0x5b, 0x36, 0x94, 0x2e, 0xd6, 0x22, 0xaa, 0xb2, 0xf9, 0xbd, 0x37, 0x1a, 0x7c, 0x85, 0x50, 0xbb, 0x5b, 0x35, 0x2a, 0xb4, 0xd2, 0x7e, 0x40, 0xb0, 0x1a, 0x15, 0x2a, 0x22, 0x10, 0x15, 0x11, 0xde, 0xee, 0x56, 0xf2, 0x13, 0xd, 0x10, 0x95, 0xe6, 0x3f, 0x63, 0x38, 0xb8, 0xdd, 0xe0, 0xdb, 0xa7, 0x61, 0x8c, 0xe2, 0x39, 0x8f, 0xc4, 0x4f, 0x4d, 0x5, 0xd6, 0x8, 0x90, 0x12, 0xcc, 0x9, 0x36, 0x35, 0xfb, 0xf9, 0xa9, 0xc3, 0xd2, 0xa9, 0x46, 0x45, 0xff, 0x56, 0x6d, 0x7e, 0xcc, 0x90, 0xdf, 0x84, 0xd9, 0xb, 0x2b, 0x3e, 0x87, 0x79, 0x44, 0x68, 0x62, 0x89, 0x68, 0xc9, 0x58, 0xa3, 0xf5, 0x9e, 0x43, 0x4c, 0xfd, 0x6d, 0x5d, 0x89, 0x2e, 0xd, 0x8, 0x9e, 0xd, 0xb8, 0x2, 0x7, 0x7f, 0x1, 0x61, 0xd1, 0x9d, 0x23, 0x58, 0xc8, 0xe1, 0x8f, 0x5d, 0x58, 0xa6, 0x33, 0xe3, 0xa9, 0x11, 0xf4, 0x58, 0x34, 0xc2, 0xec, 0x20, 0xdb, 0xeb, 0x1, 0x4a, 0x6, 0x7e, 0xae, 0x11, 0x4a, 0x7a, 0xa6, 0x1f, 0x1c, 0xe6, 0x6f, 0xd3, 0x24, 0x99, 0xb3, 0xa1, 0xb8, 0xb6, 0x33, 0xe9, 0x9a, 0xdd, 0xe, 0xb6, 0x7f, 0x74, 0x94, 0xf0, 0xa2, 0x47, 0x1, 0xf8, 0x71, 0x22, 0xd5, 0x6e, 0x5b, 0x49, 0x72, 0xc2, 0x24, 0x3f, 0xf0, 0x65, 0x18, 0x61, 0x3a, 0x7f, 0x1, 0x8e, 0x93, 0x4b, 0x1a, 0x6a, 0xe4, 0xb3, 0x4b, 0xa7, 0xf1, 0x60, 0x9f, 0x32, 0xfc, 0xd2, 0x62, 0x21, 0x48, 0xf9, 0xe, 0xd2, 0x65, 0x71, 0xc0, 0x13, 0x6a, 0xe7, 0xd8, 0xfe, 0xfb, 0x81, 0xca, 0x60, 0xd7, 0xfd, 0x78, 0x8c, 0xb3, 0xa5, 0x5c, 0x4f, 0xd4, 0x5, 0x6f, 0x2b, 0xa7, 0xb5, 0xf0, 0x45, 0xb, 0xc9, 0x2f, 0x3c, 0x84, 0x8e, 0xd9, 0x7c, 0xda, 0x63, 0xb, 0xc6, 0xef, 0xd8, 0xd7, 0x84, 0xa5, 0xb6, 0x7e, 0xbc, 0xb0, 0xb6, 0xa0, 0x60, 0xf2, 0xba, 0xfd, 0x29, 0xa3, 0xf7, 0x6b, 0x5c, 0x13, 0xe3, 0x46, 0x60, 0xae, 0x1a, 0xf6, 0x49, 0x8a, 0xcd, 0x99, 0xe4, 0xd8, 0x3c, 0x90, 0x6f, 0xc5, 0x3b, 0x98, 0xff, 0xea, 0x91, 0x1f, 0x3, 0xaa, 0x14, 0xb8, 0x82, 0x17, 0xc8, 0xfb, 0x49, 0x18, 0xb0, 0xf9, 0x9d, 0x5b, 0xe7, 0x76, 0xe5, 0x9b, 0x95, 0xa5, 0xf, 0x1e, 0xfe, 0xbf, 0xb8, 0x3f, 0x70, 0x44, 0xba, 0x8e, 0xcc, 0xf, 0xab, 0xcd, 0xc5, 0x8c, 0xd8, 0x32, 0x5e, 0x99, 0xae, 0x52, 0x5c, 0x5f, 0x61, 0x3f, 0xa, 0x4c, 0x45, 0x6, 0x68, 0xcc, 0x99, 0xc5, 0xe5, 0x15, 0x4a, 0xd5, 0x18, 0x60, 0x21, 0x7b, 0x7a, 0x9b, 0x48, 0x7b, 0x5d, 0x28, 0x7c, 0x8, 0x73, 0x2f, 0x40, 0x48, 0x71, 0x15, 0xdc, 0x7c, 0x8c, 0x99, 0xc2, 0xc3, 0x57, 0xa9, 0xc3, 0xdc, 0x24, 0x37, 0x70, 0x4b, 0xac, 0xd1, 0xc4, 0x86, 0x4e, 0x24, 0x5e, 0x5f, 0x56, 0x90, 0xf7, 0x40, 0xa6, 0x38, 0x31, 0xa4, 0x3e, 0x2c, 0xb, 0xc8, 0xa8, 0xd8, 0x5, 0xb2, 0x69, 0x2c, 0x8f, 0x41, 0xdc, 0x61, 0x64, 0x43, 0x8e, 0x46, 0x94, 0x27, 0xf9, 0x28, 0x72, 0x92, 0xd8, 0x37, 0xd0, 0xc3, 0x5d, 0x8f, 0x48, 0x83, 0x98, 0x6a, 0x4, 0xae, 0xea, 0xa4, 0x55, 0x96, 0xaa, 0xb, 0xb0, 0x57, 0x27, 0x5a, 0xc7, 0xad, 0x9d, 0x9e, 0x24, 0xba, 0xa0, 0xe8, 0xf5, 0xfe, 0xd5, 0x92, 0x1d, 0xb5, 0x9d, 0x7c, 0xf0, 0x98, 0xcf, 0x9d, 0xe9, 0xd2, 0x3c, 0x4, 0x39, 0xd3, 0x6c, 0xbc, 0xd6, 0x96, 0x58, 0xc8, 0x10, 0xd9, 0x27, 0xe6, 0x85, 0x84, 0x36, 0x50, 0xa3, 0xeb, 0xf3, 0x70, 0xb5, 0x2a, 0x89, 0x16, 0x49, 0xa7, 0x20, 0x24, 0xd8, 0xf5, 0x2f, 0x80, 0xaf, 0xf9, 0x43, 0xd7, 0xc9, 0x67, 0xb3, 0x9d, 0xb3, 0xd3, 0x1a, 0x5e, 0x3, 0x2f, 0xa7, 0x84, 0x8f, 0x5, 0xbd, 0xdd, 0xe1, 0x22, 0x79, 0x5c, 0xa1, 0x1d, 0xcb, 0xce, 0x58, 0xee, 0x42, 0xf5, 0x2d, 0x6b, 0xad, 0xf8, 0xa5, 0x25, 0x14, 0xfd, 0xf0, 0xb4, 0x34, 0x9c, 0xf1, 0xaf, 0x7d, 0x57, 0x19, 0xb6, 0xd3, 0x29, 0x7c, 0x76, 0x63, 0xa8, 0x85, 0x27, 0xa0, 0x4, 0x24, 0x72, 0x9b, 0x84, 0xd4, 0x3d, 0x12, 0x2d, 0x4e, 0x3a, 0xc8, 0x65, 0xcd, 0x15, 0x8d, 0xac, 0x85, 0x3c, 0x83, 0x44, 0xa4, 0x4f, 0xa8, 0x50, 0xfe, 0xd, 0xda, 0x81, 0x44, 0xf9, 0x8a, 0xdd, 0xd5, 0x41, 0xa1, 0x75, 0x37, 0x96, 0x1a, 0xe8, 0xc5, 0x6b, 0x2b, 0x1c, 0x1d, 0x1a, 0x3d, 0x1, 0xa4, 0xdf, 0x24, 0xa9, 0x78, 0x67, 0xc9, 0x58, 0x78, 0x89, 0x77, 0x54, 0x32, 0x6d, 0x7d, 0xb2, 0x1f, 0xe3, 0xbf, 0x43, 0x83, 0xf4, 0x7e, 0x50, 0xe7, 0x8a, 0x63, 0xdd, 0xec, 0xa0, 0x92, 0x32, 0x61, 0xb1, 0x7, 0x6a, 0xa6, 0x50, 0xe6, 0x2d, 0x36, 0x44, 0x70, 0x31, 0x5, 0xc2, 0x74, 0x75, 0xd0, 0xec, 0xa9, 0x60, 0x67, 0xad, 0xfe, 0xb5, 0x7f, 0x9f, 0x8f, 0xa2, 0x99, 0x14, 0x8d, 0x5e, 0xb7, 0xe4, 0xef, 0xf0, 0xce, 0x47, 0x67, 0x88, 0x76, 0x26, 0xa9, 0x85, 0x44, 0x9, 0xbf, 0x3c, 0xce, 0xe6, 0xe5, 0xee, 0x7b, 0xc7, 0x56, 0xfa, 0x28, 0xfc, 0x3c, 0xd1, 0xda, 0x4a, 0xc1, 0xc0, 0x3b, 0xd, 0xf9, 0x8c, 0x79, 0xd4, 0xaf, 0x59, 0x12, 0xf, 0x9f, 0xf3, 0x64, 0xf3, 0x2, 0x94, 0xc7, 0x12, 0x9f, 0x8b, 0xc8, 0x9e, 0xcf, 0x22, 0x7, 0xea, 0xca, 0x9c, 0x1e, 0xfe, 0xa4, 0xbb, 0x48, 0x5c, 0xe3, 0x8a, 0xf6, 0xf7, 0x9d, 0xf6, 0x66, 0x26, 0x6c, 0xe5, 0x5a, 0xf, 0xc8, 0x43, 0x3d, 0xe9, 0x64, 0xc9, 0x8e, 0xa9, 0x16, 0x70, 0xb8, 0xcc, 0x69, 0xf, 0xf5, 0x8c, 0xea, 0xbb, 0xb3, 0x94, 0x30, 0x9e, 0xf5, 0x12, 0xe6, 0xbd, 0x39, 0xc5, 0x2c, 0x43, 0x7f, 0xfd, 0x61, 0xe3, 0xb9, 0xbb, 0xd3, 0x73, 0xbd, 0xd2, 0xf8, 0x5c, 0xa6, 0x76, 0x10, 0x52, 0x68, 0x18, 0x27, 0xfd, 0x35, 0x69, 0xf4, 0x99, 0x8d, 0x15, 0xe1, 0x1c, 0xc5, 0x31, 0x78, 0x2a, 0xdd, 0xda, 0x66, 0x27, 0x51, 0x71, 0xf8, 0xca, 0x3e, 0x58, 0xe4, 0x4a, 0xc, 0xa, 0x1b, 0x5f, 0x17, 0xd5, 0x9c, 0xb4, 0x9e, 0x5b, 0x8f, 0x4d, 0x86, 0xe2, 0x7a, 0x32, 0x4a, 0x74, 0x40, 0x5d, 0xbe, 0xa2, 0x1a, 0x8a, 0xa9, 0x90, 0x60, 0x5a, 0xc4, 0x3, 0x88, 0x65, 0x79, 0x8, 0xc2, 0x8a, 0x9, 0xcc, 0x90, 0xc0, 0x1a, 0xdb, 0xb8, 0xdb, 0xf2, 0xc6, 0x6b, 0x7f, 0xb0, 0xe4, 0xa9, 0x45, 0x6e, 0xa5, 0x6f, 0x85, 0xc9, 0xbc, 0x80, 0xec, 0x84, 0xc4, 0x44, 0x8, 0xd3, 0x89, 0xcc, 0x3a, 0x70, 0x60, 0x82, 0xd3, 0xd7, 0x8f, 0xe9, 0x92, 0x28, 0x96, 0xb6, 0xb6, 0xfa, 0x1f, 0x6e, 0x58, 0x88, 0xd, 0x4f, 0xb3, 0xf6, 0xfc, 0xf1, 0xe, 0xd4, 0x21, 0x35, 0xca, 0x97, 0x64, 0xa3, 0xa2, 0x1e, 0x10, 0x18, 0x5, 0x4d, 0x1e, 0xbc, 0xd9, 0x4a, 0xb6, 0x96, 0xc9, 0x51, 0xf9, 0x76, 0xaa, 0xd0, 0x96, 0x75, 0xb5, 0x6a, 0x81, 0xcf, 0x27, 0xa, 0x7f, 0xf6, 0xf, 0x18, 0xf2, 0x16, 0x82, 0x96, 0x8, 0xb0, 0x70, 0xa7, 0x2, 0xbd, 0x2f, 0x2, 0xa9, 0x56, 0xae, 0xa4, 0xc7, 0xd8, 0x78, 0xd2, 0xe2, 0x88, 0x1d, 0xd9, 0x29, 0xfc, 0x60, 0xcc, 0x92, 0x0, 0x3a, 0xd, 0x4e, 0xb7, 0xe5, 0x9, 0xc2, 0x9e, 0xfd, 0x20, 0xcb, 0xaf, 0x4c, 0xcd, 0x69, 0x79, 0x27, 0x5a, 0xd, 0x11, 0x60, 0x32, 0x41, 0xd6, 0xc6, 0x13, 0xaf, 0xe, 0xe9, 0x4, 0x6f, 0xd, 0x75, 0x1c, 0xb3, 0x79, 0x11, 0xd3, 0x77, 0x73, 0x6a, 0xa8, 0x1e, 0x46, 0x9d, 0xa, 0xbe, 0x39, 0x60, 0x23, 0x93, 0x3, 0xcf, 0x97, 0xee, 0xd8, 0x78, 0xa5, 0xe0, 0xa9, 0x19, 0xee, 0x9f, 0xac, 0x77, 0x2d, 0xf8, 0x50, 0x3a, 0x1b, 0xb1, 0x64, 0x9e, 0x12, 0xe7, 0xd3, 0x29, 0x2c, 0xbd, 0xdf, 0xe0, 0xe2, 0x97, 0xfc, 0x4a, 0xd6, 0x60, 0xa, 0x90, 0xfc, 0x63, 0x55, 0x94, 0x7b, 0x14, 0x85, 0x5f, 0xba, 0xef, 0xca, 0x74, 0x3c, 0x39, 0x47, 0xc2, 0xe9, 0xba, 0x9b, 0xcf, 0xb2, 0x69, 0xc4, 0x4c, 0xda, 0x95, 0x52, 0x9e, 0x53, 0x84, 0x8b, 0x4b, 0x9e, 0xec, 0x67, 0x4, 0x30, 0x76, 0x5a, 0x3e, 0x7f, 0xbe, 0x79, 0xbb, 0xbf, 0xbd, 0x3, 0x16, 0xa8, 0x9f, 0xb, 0xb2, 0x33, 0xd5, 0xdb, 0x59, 0xf5, 0x94, 0xe6, 0x48, 0xe5, 0x3e, 0xcb, 0x12, 0xd7, 0xbe, 0x8a, 0x83, 0x44, 0x6e, 0x6b, 0x66, 0x5e, 0x6, 0xb7, 0x40, 0x1c, 0xbd, 0x1b, 0x56, 0xfb, 0x3a, 0xb6, 0x13, 0xbe, 0x81, 0xab, 0xd7, 0xe1, 0x99, 0x76, 0x40, 0xda, 0x26, 0xa6, 0xb6, 0xdc, 0xed, 0x17, 0xde, 0x64, 0x2f, 0xac, 0x2f, 0xac, 0xbd, 0xa9, 0x13, 0xd2, 0xbf, 0x90, 0xa4, 0xed, 0x15, 0xb, 0x2f, 0x6c, 0xbe, 0x4b, 0xd0, 0x78, 0x97, 0xfe, 0xde, 0xda, 0x49, 0x79, 0x74, 0x66, 0x15, 0x57, 0x4, 0x6f, 0xd, 0xca, 0x7a, 0x9a, 0x86, 0xdd, 0x53, 0x14, 0xbe, 0x79, 0xda, 0xda, 0x91, 0x98, 0xfb, 0x2e, 0x72, 0x63, 0x6d, 0xa0, 0x33, 0xc7, 0x4d, 0xfb, 0xb8, 0xef, 0xb6, 0x86, 0x92, 0x61, 0x10, 0x5, 0xb5, 0x8b, 0x20, 0x66, 0xf9, 0x1b, 0xbe, 0x8c, 0x13, 0x58, 0x4c, 0x66, 0x68, 0x9a, 0x92, 0x3a, 0x51, 0x2e, 0xe2, 0x9d, 0x8, 0xdc, 0x1d, 0x44, 0x80, 0xd, 0x44, 0x10, 0x85, 0x5d, 0x5d, 0x8a, 0x6b, 0x67, 0x33, 0xa1, 0x4d, 0xfc, 0x88, 0xdf, 0x77, 0x62, 0x2, 0x17, 0x78, 0xf5, 0x5, 0xb3, 0x45, 0x6c, 0x76, 0x49, 0x2f, 0xc1, 0x79, 0x45, 0x5d, 0xd8, 0x70, 0xbe, 0x64, 0xe5, 0xec, 0xbc, 0x44, 0x45, 0x3c, 0x3f, 0xaf, 0xcf, 0x39, 0x4b, 0x9a, 0xbe, 0xf4, 0xd3, 0x95, 0xcb, 0x57, 0xc, 0xa6, 0xb6, 0xba, 0x4, 0xb4, 0x8c, 0x5, 0xc2, 0xf2, 0x65, 0xe8, 0xe6, 0xa7, 0xdb, 0x16, 0xe7, 0x65, 0x97, 0x4e, 0x23, 0x8f, 0x78, 0x64, 0xe2, 0x4f, 0x31, 0x82, 0xdd, 0x83, 0x97, 0x45, 0xf2, 0xf9, 0xeb, 0xde, 0x26, 0x5e, 0x2e, 0xf9, 0xf5, 0x15, 0x51, 0xea, 0x1f, 0xf8, 0xcd, 0xfb, 0xdb, 0x12, 0x78, 0xb1, 0x22, 0x17, 0xb5, 0x15, 0x3d, 0x9e, 0xab, 0xfb, 0x7f, 0x4d, 0x92, 0x5c, 0x52, 0xfe, 0x4e, 0x3f, 0xcd, 0x3f, 0x20, 0xd5, 0x91, 0x23, 0x79, 0xa, 0x18, 0xc7, 0x22, 0xca, 0xee, 0xee, 0x2a, 0x6c, 0x2e, 0x7c, 0xf, 0xbe, 0xfb, 0x62, 0xfc, 0x8d, 0x7d, 0xdd, 0x88, 0xfc, 0x1b, 0x5e, 0x8c, 0xbc, 0xe5, 0xda, 0xd3, 0x2e, 0x8a, 0x91, 0x27, 0x26, 0xe5, 0xa6, 0x1b, 0xda, 0xa6, 0x2a, 0x8b, 0x9d, 0x46, 0xf, 0x1d, 0x57, 0x3c, 0x19, 0x6a, 0x5c, 0x7c, 0x9b, 0x36, 0x82, 0xe9, 0x1a, 0x7e, 0xf6, 0x6e, 0xab, 0xb1, 0x7a, 0x2d, 0x30, 0xb, 0x27, 0x4e, 0x2f, 0x8d, 0x8c, 0xee, 0x45, 0xbb, 0xbb, 0xad, 0x36, 0x44, 0xb4, 0xed, 0x53, 0x37, 0xfb, 0xd0, 0x84, 0x9a, 0x26, 0xb4, 0xad, 0xd9, 0xde, 0x3, 0x99, 0xb8, 0xf2, 0xa7, 0x3e, 0x9f, 0xfd, 0xfe, 0xbb, 0x84, 0x6e, 0x36, 0x9e, 0xef, 0x67, 0x1d, 0x69, 0x97, 0xf9, 0x8a, 0x6b, 0x57, 0xce, 0x95, 0x60, 0xdf, 0x7c, 0x8, 0x81, 0x95, 0xff, 0x62, 0xb8, 0xd2, 0x1c, 0x2, 0xaa, 0x53, 0x17, 0xb9, 0xdd, 0x96, 0x13, 0xca, 0xfb, 0xe5, 0xf5, 0x75, 0xcf, 0x2e, 0x15, 0x85, 0xf1, 0xad, 0xaf, 0x36, 0x72, 0x68, 0xe1, 0x21, 0xee, 0xcb, 0x5d, 0x14, 0xd8, 0xf, 0x79, 0x75, 0x8f, 0x1b, 0x88, 0x93, 0x3, 0x8b, 0xb2, 0xd6, 0xb8, 0x65, 0xe0, 0x47, 0xbd, 0xc2, 0x34, 0x38, 0x78, 0x37, 0x84, 0x97, 0x88, 0x94, 0x62, 0xfb, 0xa5, 0xae, 0x42, 0x3c, 0x34, 0x8e, 0x48, 0x4e, 0x79, 0xe2, 0x21, 0x17, 0xb2, 0x34, 0x3, 0xa1, 0xf2, 0x75, 0xad, 0x66, 0x5f, 0x9e, 0x31, 0xe8, 0x8d, 0xb7, 0x72, 0xfe, 0x3b, 0xaa, 0xae, 0xe8, 0xd7, 0xd5, 0x24, 0x31, 0x1d, 0x69, 0x9, 0x8b, 0x10, 0xc5, 0x75, 0xf2, 0xf9, 0xb1, 0x2b, 0x1e, 0xd, 0xd5, 0xf8, 0x31, 0x75, 0x2c, 0x37, 0xdf, 0x70, 0x7b, 0x4, 0x8c, 0x69, 0x75, 0xa4, 0x2b, 0x32, 0xbe, 0x70, 0xbf, 0xe, 0x42, 0xf9, 0xb1, 0xdf, 0x1b, 0x3d, 0xda, 0xfc, 0x5f, 0xe8, 0xe8, 0x15, 0x61, 0x32, 0xb1, 0x20, 0x1a, 0xc9, 0x16, 0xb8, 0x5f, 0xa, 0x24, 0xb4, 0x2c, 0xf6, 0x62, 0xb4, 0xf3, 0x7f, 0x8e, 0x10, 0xe, 0xaf, 0x7, 0xd, 0x67, 0x7d, 0xeb, 0x36, 0xba, 0x39, 0xe5, 0x31, 0x3b, 0x3, 0x49, 0xb1, 0xf4, 0xd6, 0xe2, 0xeb, 0x7f, 0x1f, 0xbe, 0xf0, 0xae, 0xdd, 0x72, 0x9, 0x7a, 0xf8, 0x86, 0xe7, 0xae, 0x8, 0xff, 0x14, 0xf8, 0x44, 0x86, 0x27, 0xcb, 0x1d, 0x5f, 0x17, 0x27, 0x37, 0x74, 0xa3, 0xa0, 0xb9, 0x42, 0x12, 0xdd, 0xdd, 0xdc, 0x9a, 0x4d, 0xb7, 0xa7, 0xfd, 0xf9, 0xf0, 0xf3, 0x72, 0x29, 0xae, 0x83, 0xc5, 0x35, 0xae, 0x90, 0xc9, 0xbb, 0x5c, 0xda, 0x65, 0xb, 0x1a, 0xcc, 0x62, 0x2a, 0xa7, 0x2a, 0xe2, 0x83, 0x64, 0x9e, 0x13, 0xda, 0x75, 0xd6, 0xe2, 0x5a, 0xab, 0xb8, 0x6f, 0x4f, 0x73, 0x75, 0x68, 0xb8, 0x21, 0x7f, 0x1, 0xa8, 0xc8, 0x3c, 0x65, 0x60, 0xfa, 0xf8, 0x6, 0x2a, 0xc, 0xc3, 0x32, 0xa2, 0xe, 0x67, 0xa1, 0x78, 0xc6, 0xd3, 0x25, 0xae, 0x28, 0x95, 0x4f, 0x17, 0xf4, 0x65, 0xe7, 0x49, 0xd1, 0x4f, 0x3b, 0x12, 0xe, 0x9d, 0xbe, 0x8b, 0x29, 0xf, 0x65, 0x94, 0x65, 0x8b, 0x29, 0x37, 0xa, 0xb, 0x58, 0x4c, 0x77, 0xdd, 0x59, 0xe4, 0xd5, 0xf2, 0x33, 0x1a, 0xb3, 0x7e, 0xf, 0x9a, 0x71, 0x18, 0x31, 0xe2, 0x68, 0x5, 0xab, 0x6c, 0xe7, 0xa3, 0x95, 0x63, 0x4c, 0xd2, 0xf3, 0x4b, 0xe2, 0x8e, 0x0, 0xe5, 0x96, 0xae, 0xe7, 0x4, 0x14, 0x9d, 0x63, 0x1, 0x8d, 0x85, 0x7c, 0xb7, 0x24, 0xc7, 0xb2, 0xea, 0x17, 0x64, 0x8a, 0x1f, 0xfc, 0xcc, 0xb2, 0xbe, 0xc2, 0xd7, 0xd1, 0x79, 0xd, 0x14, 0xd9, 0x75, 0x22, 0xed, 0x46, 0x85, 0xd2, 0xc7, 0xcb, 0x7, 0x10, 0x92, 0x7, 0x15, 0xf5, 0xa5, 0x30, 0x79, 0xe1, 0x82, 0x3d, 0x8a, 0x45, 0x35, 0xcf, 0x83, 0x2c, 0x95, 0x2a, 0x7, 0x9e, 0x3b, 0xbb, 0x5d, 0x4f, 0xd3, 0xed, 0xe9, 0x23, 0x5b, 0x62, 0x53, 0xbb, 0xde, 0x3c, 0x30, 0x31, 0xc9, 0x5f, 0x40, 0x49, 0x82, 0x2a, 0xb3, 0xa6, 0x4, 0xbb, 0xd4, 0x6f, 0x96, 0x30, 0x11, 0x2f, 0xcd, 0x4d, 0xba, 0xe3, 0x62, 0xaf, 0x12, 0xb7, 0x11, 0x60, 0x7c, 0x80, 0x6e, 0x51, 0x4b, 0xa0, 0x50, 0x39, 0xcc, 0x26, 0xe1, 0x38, 0x81, 0xdd, 0x11, 0x1c, 0x99, 0xb8, 0x33, 0x73, 0x6e, 0xe7, 0x4f, 0xeb, 0xfd, 0x4c, 0xaa, 0x14, 0xeb, 0xad, 0xce, 0x58, 0x66, 0x81, 0xc, 0xba, 0x33, 0xa, 0x45, 0xa4, 0x68, 0xc, 0x9d, 0x5d, 0xf9, 0x62, 0x44, 0xa5, 0x6c, 0x79, 0x72, 0x21, 0x2d, 0x27, 0x4a, 0xa5, 0x6d, 0x29, 0x48, 0xb9, 0x7, 0x5d, 0x28, 0x98, 0x36, 0x86, 0xf6, 0x2f, 0xa4, 0x45, 0xd0, 0x5d, 0xad, 0x78, 0x66, 0x16, 0xa6, 0x75, 0x39, 0xd3, 0x7d, 0xce, 0xc6, 0x55, 0x40, 0x2a, 0xb7, 0x1, 0x27, 0x52, 0xe2, 0xa7, 0xa5, 0x8b, 0xdc, 0xf3, 0xc3, 0xd, 0xed, 0x95, 0x44, 0x4c, 0xea, 0x51, 0xe2, 0xd7, 0x50, 0x84, 0x25, 0x77, 0x1b, 0x97, 0x69, 0xa1, 0x27, 0xd0, 0xfe, 0x62, 0x80, 0x92, 0xba, 0x6d, 0x22, 0xd8, 0xb5, 0xab, 0x3f, 0x5d, 0xe7, 0x2f, 0xd2, 0xb9, 0xe4, 0xcd, 0xf2, 0x1, 0xb9, 0x40, 0x4d, 0x8, 0x48, 0x7f, 0x1, 0x5e, 0xf7, 0x15, 0x9, 0xc4, 0x94, 0xa, 0x58, 0x99, 0xeb, 0xce, 0x3c, 0xbc, 0xe3, 0xdf, 0x67, 0x90, 0x25, 0x5c, 0xac, 0x66, 0xfb, 0x49, 0xb6, 0x19, 0xc4, 0xa2, 0x87, 0xbe, 0x3c, 0x9e, 0xf2, 0xff, 0x18, 0x52, 0x6b, 0xa4, 0x47, 0x80, 0xc6, 0x74, 0xdf, 0x43, 0xa, 0xed, 0x71, 0x26, 0x43, 0x33, 0xce, 0x53, 0x6e, 0x52, 0xbb, 0x2e, 0x84, 0x49, 0xc2, 0xae, 0xdd, 0x1c, 0x1e, 0x3, 0xd5, 0xd2, 0x10, 0xa5, 0xe8, 0xc9, 0x55, 0xbe, 0x7b, 0x9d, 0x4f, 0x1, 0xb1, 0xc3, 0xfa, 0xba, 0x29, 0xf2, 0x3d, 0x1c, 0xa, 0x5a, 0x20, 0x64, 0x4d, 0x90, 0xce, 0x9d, 0x75, 0x6d, 0x50, 0xce, 0xb9, 0x36, 0x66, 0xf0, 0xbe, 0x9b, 0xfb, 0xd2, 0xbb, 0xcb, 0x8d, 0x8b, 0xa2, 0x39, 0xc4, 0x48, 0xdb, 0xe4, 0x25, 0xb3, 0x84, 0xcf, 0x83, 0x78, 0xad, 0xa, 0xdf, 0x93, 0x2a, 0xdf, 0xc5, 0xce, 0xa9, 0xbc, 0x65, 0x5f, 0xa7, 0x29, 0xdb, 0x64, 0xe4, 0x17, 0xa0, 0x6f, 0xf1, 0x26, 0x1, 0x4b, 0x6e, 0x98, 0x3d, 0x6a, 0xe6, 0x3c, 0xc3, 0x36, 0x60, 0x5, 0xa7, 0xe3, 0xbd, 0xb6, 0x76, 0xac, 0x19, 0x67, 0xbf, 0xcb, 0x1d, 0xc9, 0x8b, 0x7c, 0x42, 0xa4, 0x17, 0x87, 0x45, 0x91, 0xbe, 0x2a, 0xbf, 0xf, 0x8d, 0xb, 0xe, 0xce, 0xa4, 0xb0, 0x29, 0xc0, 0x60, 0x97, 0xdf, 0x84, 0x6c, 0x25, 0xa6, 0x51, 0x73, 0xc2, 0x16, 0x67, 0xc, 0xc8, 0x43, 0x60, 0x8e, 0x61, 0xbd, 0x11, 0xa5, 0x7f, 0x1, 0x99, 0xc7, 0xdd, 0x4a, 0xe3, 0xc1, 0x99, 0x9, 0xd1, 0x7e, 0x7c, 0xcc, 0x1e, 0xf2, 0x93, 0xf6, 0x2b, 0x5e, 0x54, 0x5b, 0x9e, 0x5b, 0xb4, 0x70, 0x24, 0x52, 0x33, 0x5e, 0xa6, 0x17, 0xa, 0x97, 0xad, 0xa5, 0x86, 0xc2, 0x26, 0xde, 0x65, 0xcc, 0xf8, 0x3f, 0x7, 0x3d, 0xb1, 0xc0, 0x5b, 0x4f, 0xb6, 0xd3, 0x69, 0xc2, 0xce, 0xb6, 0x11, 0x62, 0xac, 0xed, 0x96, 0x5, 0x1f, 0xf0, 0xbb, 0x6a, 0x1e, 0x4c, 0x95, 0x3, 0xed, 0x4c, 0x1, 0x43, 0x98, 0xd6, 0x32, 0x16, 0x7b, 0xf7, 0x57, 0x3a, 0x7d, 0xae, 0x5, 0xe4, 0xe, 0xfc, 0x61, 0x7f, 0x1, 0xb9, 0x4d, 0xb8, 0xc4, 0x79, 0xad, 0xbe, 0xe0, 0x77, 0xea, 0x6c, 0x77, 0xa5, 0x8, 0xea, 0xe, 0x63, 0x8e, 0xa2, 0x2f, 0x5b, 0x7a, 0x6e, 0xae, 0x47, 0x97, 0x7f, 0x1, 0xbd, 0x82, 0xea, 0x4b, 0x34, 0x33, 0xe4, 0x2b, 0x26, 0x5, 0x8, 0x24, 0x52, 0xdb, 0xf, 0xc0, 0x8a, 0x6d, 0xfc, 0x8b, 0x27, 0xd8, 0x6b, 0x9, 0xc1, 0x61, 0x5, 0x75, 0x75, 0xbe, 0xe3, 0x2b, 0x2b, 0x7, 0x62, 0xc0, 0x9d, 0x6f, 0xd7, 0x74, 0x22, 0xa, 0x9, 0xe1, 0xe5, 0xce, 0xb, 0x38, 0x54, 0xa8, 0x27, 0xe7, 0x1e, 0xf7, 0xce, 0x25, 0x79, 0xc9, 0x43, 0xbb, 0x4a, 0x81, 0x14, 0x1, 0x2b, 0xaa, 0xc4, 0x70, 0xfa, 0x9c, 0x82, 0x16, 0xca, 0x58, 0x8b, 0xeb, 0x51, 0x62, 0xe6, 0xf6, 0x5, 0xb4, 0x5b, 0x3a, 0x1d, 0xff, 0x70, 0x45, 0xb, 0x5c, 0xff, 0xb0, 0x4f, 0x98, 0x2d, 0xf8, 0x21, 0x4e, 0x25, 0xf2, 0xe6, 0x1a, 0x6a, 0x33, 0xd9, 0xee, 0xad, 0xdd, 0x19, 0x95, 0x39, 0x30, 0xb3, 0xd4, 0xd5, 0x96, 0xe9, 0x2e, 0xe8, 0x1d, 0x86, 0xf2, 0x6e, 0xf6, 0xba, 0x88, 0xf3, 0x72, 0xf, 0xf0, 0x2c, 0x2d, 0x58, 0xbe, 0x20, 0x94, 0x27, 0x96, 0xe4, 0xa4, 0x9d, 0x3b, 0xb2, 0x6, 0x45, 0x11, 0xb8, 0x3f, 0xe, 0x59, 0x68, 0xf5, 0xd8, 0xb4, 0xba, 0xd0, 0xb5, 0x47, 0x1e, 0xc1, 0x8a, 0x57, 0xf2, 0x16, 0x4c, 0xea, 0xf1, 0x7a, 0x5d, 0xc9, 0xeb, 0x25, 0x72, 0x57, 0x52, 0x47, 0x2f, 0x14, 0x90, 0xc7, 0x5b, 0x10, 0x8e, 0xd6, 0x58, 0x1b, 0x48, 0xd4, 0x3b, 0x14, 0xef, 0x23, 0x95, 0x6a, 0x88, 0x6c, 0x10, 0x66, 0xfd, 0x3c, 0x3d, 0x7f, 0xc5, 0x2c, 0x15, 0xbc, 0x4d, 0xe4, 0x4f, 0xef, 0x53, 0xa6, 0x83, 0xb1, 0x55, 0xeb, 0xe3, 0xee, 0x68, 0xde, 0xd5, 0x9d, 0x84, 0x39, 0xdf, 0x33, 0x27, 0xb, 0xb9, 0xc9, 0x25, 0xa6, 0x8c, 0xa2, 0x62, 0x24, 0x4d, 0x2, 0x2b, 0x58, 0xa6, 0x4a, 0x80, 0x4d, 0x74, 0x4c, 0xca, 0x74, 0xf5, 0x4c, 0x3, 0x79, 0x8d, 0x76, 0x4f, 0xc5, 0xb8, 0xe2, 0x3a, 0x38, 0xf5, 0xcd, 0x4d, 0x89, 0x43, 0x34, 0xa7, 0xcb, 0xf4, 0x85, 0x99, 0xcf, 0x2f, 0xc5, 0xed, 0x21, 0x8, 0x2, 0xb6, 0x67, 0x72, 0x86, 0xa3, 0x8d, 0xba, 0xd9, 0x4e, 0xf6, 0x6c, 0xcf, 0x24, 0xef, 0xee, 0x73, 0x8a, 0x85, 0x11, 0xd2, 0xbd, 0x63, 0x89, 0x6b, 0x7f, 0x44, 0x87, 0xa, 0xe6, 0x6a, 0xd3, 0xdb, 0xda, 0x8a, 0xe5, 0xce, 0x38, 0x79, 0xc5, 0x21, 0x40, 0xe3, 0xc4, 0x50, 0x83, 0xd7, 0x84, 0x91, 0xf3, 0x4a, 0x3c, 0x5a, 0xe2, 0x2c, 0x1b, 0x38, 0xa9, 0xab, 0x7b, 0x72, 0x36, 0xd7, 0x56, 0xbc, 0xab, 0x98, 0x4c, 0xb6, 0xee, 0x85, 0x2f, 0xba, 0xbd, 0x80, 0x3f, 0x69, 0x15, 0x51, 0xe1, 0xbc, 0x13, 0x9a, 0x5d, 0x5a, 0xf2, 0x7e, 0x1d, 0xc5, 0xbf, 0x8d, 0x50, 0x14, 0xfc, 0x3e, 0xe5, 0x54, 0xb4, 0x77, 0x13, 0x96, 0x29, 0xcb, 0x5f, 0x0, 0x4b, 0x22, 0x62, 0x7a, 0x15, 0x9d, 0xb8, 0x3a, 0x33, 0xf, 0xff, 0x18, 0x44, 0x43, 0x6e, 0x2d, 0xfa, 0x52, 0x4e, 0xde, 0x51, 0x78, 0xa6, 0xc6, 0xa0, 0xfd, 0x0, 0xb6, 0xbd, 0x37, 0x84, 0xaf, 0xd4, 0x59, 0xbd, 0x31, 0x31, 0xc3, 0xe9, 0x54, 0xb5, 0x7d, 0x65, 0xc5, 0xad, 0x79, 0x25, 0xc, 0x9d, 0x9c, 0xc1, 0x40, 0xa2, 0xa7, 0xa4, 0x4d, 0x99, 0xf2, 0x4e, 0xb3, 0x20, 0xaf, 0xfe, 0xd5, 0xbd, 0x18, 0x67, 0xca, 0x84, 0x3a, 0x82, 0x8a, 0x6c, 0x4, 0x3d, 0x53, 0xa0, 0xca, 0x32, 0xb2, 0x34, 0x1d, 0x55, 0x4c, 0x31, 0x38, 0xe0, 0x9f, 0xbb, 0x10, 0xba, 0xc0, 0xc, 0x14, 0xe5, 0xbc, 0xfc, 0xcd, 0x0, 0x47, 0xf, 0xd7, 0x23, 0x18, 0xa0, 0x11, 0x2f, 0x90, 0x17, 0x2c, 0x52, 0x7c, 0xba, 0xc5, 0x24, 0x7c, 0x31, 0xbc, 0xbe, 0x2c, 0x68, 0x15, 0x78, 0x63, 0xbf, 0x51, 0x99, 0x66, 0x25, 0x4b, 0x1b, 0xbd, 0x61, 0x39, 0x38, 0x7a, 0xbb, 0xd5, 0x53, 0x38, 0xd3, 0x9a, 0x6c, 0x66, 0x33, 0xef, 0xbd, 0x22, 0x6e, 0xdc, 0x50, 0x94, 0x53, 0xea, 0xf9, 0xc1, 0x32, 0x8e, 0xdf, 0xde, 0xc3, 0x5e, 0x14, 0x7e, 0x4c, 0x36, 0x2c, 0x98, 0x8f, 0x69, 0x6c, 0xe9, 0x4a, 0x1a, 0x6b, 0xf0, 0x36, 0xd6, 0xed, 0x75, 0x37, 0x17, 0x7c, 0x9d, 0x9, 0xda, 0xf, 0x39, 0x3e, 0x24, 0xe1, 0x49, 0x30, 0x39, 0xe1, 0xfc, 0xcc, 0x2d, 0xcb, 0xe4, 0x7a, 0xfe, 0x90, 0xd9, 0x16, 0xa6, 0xdf, 0x5c, 0x80, 0x1a, 0x13, 0x57, 0xf, 0x3a, 0xcd, 0x92, 0x12, 0x9b, 0x6f, 0x6e, 0x16, 0xb8, 0xa, 0x3e, 0x84, 0x3b, 0xa7, 0x93, 0xb8, 0x2, 0xf9, 0xd9, 0xdb, 0x91, 0x26, 0x3e, 0x32, 0xa3, 0x62, 0x1f, 0xed, 0xb6, 0xba, 0xe9, 0xc, 0x2e, 0x2f, 0x66, 0x76, 0x7f, 0xdc, 0xac, 0x41, 0x14, 0x7f, 0x23, 0xa5, 0xba, 0xfc, 0x99, 0x8e, 0x29, 0x7b, 0x8f, 0x3a, 0x40, 0x60, 0xa4, 0x40, 0x25, 0xa1, 0x68, 0x67, 0xe4, 0xb8, 0x56, 0x38, 0x6b, 0x2e, 0x55, 0x1a, 0xdf, 0x27, 0xae, 0xec, 0x92, 0xb2, 0x14, 0x81, 0xcd, 0xb8, 0xd1, 0xa5, 0x22, 0xfd, 0xe8, 0xca, 0x7f, 0xd2, 0x3, 0xbb, 0xb1, 0xe, 0x4d, 0x26, 0x81, 0x91, 0x5c, 0x7e, 0x7, 0x84, 0x7d, 0x26, 0x8d, 0xf2, 0x80, 0xe6, 0x5e, 0xa8, 0x6c, 0x24, 0x88, 0x4a, 0x10, 0x9a, 0x21, 0xa7, 0x70, 0x1d, 0x3f, 0xaa, 0xb6, 0x9a, 0x9c, 0x65, 0x6e, 0x42, 0xb7, 0xd6, 0xa5, 0x96, 0x4d, 0xb5, 0xe6, 0x15, 0x50, 0xe5, 0xa0, 0x21, 0xde, 0xd, 0xd6, 0xfc, 0xbf, 0xae, 0x3b, 0xb5, 0x70, 0xa5, 0x31, 0x87, 0xd7, 0x82, 0xc6, 0x8d, 0xe2, 0xc8, 0x91, 0x51, 0x7, 0x92, 0x20, 0xd3, 0xa3, 0x86, 0x86, 0xc4, 0x5d, 0xbc, 0xe2, 0xaa, 0xe5, 0xfe, 0x2, 0x7e, 0x53, 0xfb, 0xf3, 0x3c, 0xc9, 0x96, 0x1a, 0x1e, 0xa8, 0xc5, 0x88, 0x6d, 0xbe, 0x5d, 0x13, 0x8b, 0x3f, 0x33, 0x3a, 0x2, 0xec, 0x38, 0x19, 0x6f, 0xa0, 0x3d, 0xb3, 0x6d, 0x79, 0xf0, 0x97, 0xc6, 0xa5, 0xdb, 0x2, 0x97, 0xb1, 0x6e, 0x8c, 0xab, 0xc2, 0x26, 0x3e, 0x3f, 0x6b, 0x1f, 0x5d, 0xde, 0x9c, 0xa5, 0x71, 0x5f, 0x53, 0xc8, 0x98, 0x53, 0x3f, 0xa0, 0x3b, 0x3f, 0xfc, 0xd2, 0x7c, 0x70, 0x1c, 0x63, 0x68, 0x96, 0x98, 0xa4, 0xbd, 0xa5, 0xa, 0xe8, 0x7f, 0x4d, 0x25, 0x43, 0xd9, 0x5a, 0x6e, 0x79, 0xb1, 0x80, 0x2, 0x92, 0x45, 0x8e, 0xcd, 0x22, 0x74, 0xd6, 0x93, 0xe6, 0xf9, 0xdf, 0x86, 0x51, 0x7b, 0x33, 0xcc, 0x46, 0xab, 0xe7, 0xd7, 0xd1, 0x16, 0x3e, 0x3b, 0xdd, 0x8b, 0x53, 0xd1, 0x50, 0x7a, 0xa1, 0xae, 0x46, 0x9b, 0xda, 0xa5, 0xb7, 0x4, 0xe7, 0x42, 0xff, 0x2, 0x5a, 0x40, 0xba, 0x1b, 0xa3, 0x5e, 0xd3, 0xbf, 0x8f, 0x76, 0x9a, 0xa0, 0x47, 0x47, 0x1c, 0x8, 0x31, 0x4e, 0x7e, 0x4, 0x64, 0x33, 0x7a, 0xcb, 0xd8, 0xf1, 0x88, 0xc2, 0x57, 0x86, 0x71, 0x1d, 0x5b, 0xb, 0x72, 0xf5, 0xf1, 0xc5, 0xa4, 0xdb, 0x64, 0xfa, 0x16, 0x5b, 0x5a, 0xf8, 0xbf, 0x29, 0xcb, 0x68, 0xe, 0x76, 0xd, 0xa9, 0x9b, 0x6b, 0xb7, 0xbc, 0x53, 0x9c, 0x82, 0xf1, 0x17, 0x7a, 0x6c, 0x3, 0xb8, 0x99, 0xfd, 0xbb, 0xd5, 0xd7, 0x9c, 0x24, 0xa7, 0x17, 0xb7, 0xd4, 0x9c, 0xf3, 0xa1, 0x45, 0x74, 0x2e, 0x30, 0x23, 0x78, 0xcb, 0xcf, 0x79, 0x33, 0x2d, 0xb, 0x2d, 0xd2, 0x77, 0x4, 0x91, 0x4d, 0x43, 0x7d, 0x58, 0xae, 0xa5, 0x2d, 0x67, 0x64, 0xd0, 0x2e, 0xee, 0xbf, 0x80, 0x8b, 0x57, 0xed, 0xd1, 0x3f, 0xb3, 0xe9, 0x41, 0x1d, 0x25, 0xb4, 0x42, 0x20, 0x9d, 0xa0, 0xaa, 0xc3, 0x6, 0x86, 0xbf, 0x80, 0xc6, 0x7f, 0x92, 0x5f, 0x10, 0x38, 0x66, 0xc6, 0x9f, 0xb3, 0xa, 0x6d, 0xf2, 0x29, 0x6b, 0xf6, 0x99, 0x7f, 0x53, 0xdc, 0xfc, 0x94, 0xdc, 0xe2, 0x5d, 0x75, 0xba, 0xba, 0x9e, 0x1b, 0xf4, 0xd5, 0xf1, 0x69, 0x7e, 0xf7, 0x98, 0x34, 0xb1, 0x64, 0x94, 0x13, 0x3f, 0xc3, 0xc8, 0x1f, 0x7b, 0xed, 0xf2, 0xfb, 0x5, 0x2b, 0x1, 0x3, 0x44, 0xdb, 0xfc, 0xc1, 0xae, 0xe6, 0x81, 0x2e, 0xfe, 0x8f, 0x5d, 0x6c, 0xbe, 0xae, 0x9c, 0xf1, 0x6f, 0x70, 0xc6, 0xd6, 0x2b, 0xfd, 0x64, 0xea, 0x98, 0x5f, 0x7c, 0x77, 0x92, 0xfb, 0x3c, 0x24, 0x85, 0xd4, 0x26, 0xde, 0xfc, 0xc3, 0x7d, 0x1, 0xc9, 0x4, 0xa5, 0x6e, 0xe8, 0x42, 0x64, 0xdb, 0xe9, 0xcc, 0x53, 0x71, 0xba, 0x3f, 0x5b, 0x90, 0xcf, 0x1f, 0xa5, 0x37, 0xb1, 0x3c, 0x9, 0x69, 0xb2, 0xca, 0xc9, 0x4, 0xf2, 0x35, 0x9f, 0x2d, 0xb, 0xdc, 0x44, 0xbf, 0x99, 0x21, 0xd3, 0xad, 0x96, 0xd3, 0x3a, 0x3f, 0x59, 0xeb, 0x30, 0xe3, 0x30, 0xa7, 0xf5, 0x70, 0x19, 0x1b, 0x5, 0xbd, 0x49, 0x7f, 0x57, 0xce, 0x9e, 0xda, 0xbc, 0x40, 0x3a, 0x2e, 0xcf, 0x20, 0x98, 0x77, 0x7d, 0x79, 0x50, 0xf9, 0x98, 0x69, 0x60, 0x4b, 0x7d, 0x5c, 0x69, 0xdb, 0x43, 0x1f, 0x2b, 0x56, 0xe2, 0xd9, 0x88, 0xc3, 0xcc, 0xab, 0x53, 0x3e, 0x62, 0x74, 0x22, 0xa8, 0x1c, 0xdf, 0xa5, 0x4d, 0x3f, 0xde, 0x96, 0x15, 0xe, 0x2b, 0x4b, 0x80, 0xbc, 0x4b, 0x1a, 0x7b, 0x13, 0xb2, 0xd0, 0xd4, 0xf6, 0x7e, 0xa2, 0xfd, 0xd9, 0x54, 0x63, 0x1a, 0xdc, 0xaa, 0x56, 0x23, 0x6a, 0xc2, 0xc7, 0x34, 0x71, 0xbb, 0xd4, 0xf1, 0xfb, 0x3d, 0x7d, 0x9b, 0x4b, 0x43, 0x8b, 0xb1, 0xbf, 0xbc, 0xd4, 0x89, 0xfb, 0x8e, 0xcd, 0xe4, 0x44, 0x50, 0xce, 0x65, 0x40, 0x29, 0x34, 0xc, 0xaa, 0xca, 0x8d, 0x66, 0xd4, 0xf8, 0xa8, 0xbe, 0x81, 0x72, 0x5b, 0xf0, 0x17, 0xa0, 0x36, 0x6d, 0x24, 0x7b, 0xfe, 0x2a, 0xc3, 0x70, 0xa, 0xe1, 0x6f, 0xfb, 0x63, 0x5d, 0xd0, 0x50, 0xee, 0x72, 0xff, 0x98, 0x69, 0x93, 0x79, 0x99, 0xd6, 0x2d, 0xf8, 0xec, 0xd9, 0xbb, 0xd1, 0x75, 0xb5, 0xa1, 0xc0, 0xfc, 0xb1, 0x45, 0xcc, 0x12, 0x1b, 0x7, 0x45, 0x79, 0x7a, 0xb, 0x6a, 0x57, 0x95, 0xc4, 0x88, 0x1b, 0x3c, 0xc4, 0x5a, 0x55, 0x98, 0xfb, 0x16, 0x1b, 0x30, 0x4f, 0xca, 0xe6, 0xff, 0x63, 0x34, 0x8d, 0xae, 0x99, 0x3a, 0xea, 0xb, 0x51, 0x47, 0x5e, 0x10, 0xd7, 0xa3, 0x4, 0x4b, 0xf6, 0x75, 0xa5, 0x34, 0x40, 0xa7, 0x70, 0xc9, 0x7c, 0x73, 0xc1, 0x4f, 0xc1, 0x74, 0xe5, 0xb2, 0x49, 0x94, 0xc1, 0x3c, 0x98, 0x92, 0x8, 0x8b, 0xb0, 0x4a, 0xe6, 0x8d, 0x1e, 0x59, 0xbf, 0x21, 0x14, 0xe8, 0x68, 0x37, 0x1f, 0x73, 0x66, 0xb3, 0xdf, 0xda, 0xb4, 0x37, 0x8f, 0x61, 0x8c, 0xc4, 0x7b, 0x9a, 0x6, 0x63, 0x7c, 0x49, 0x6e, 0xf8, 0xc6, 0x82, 0xd1, 0xfd, 0x39, 0x36, 0x33, 0xa, 0x6d, 0x47, 0x5a, 0xa3, 0x4b, 0x98, 0x55, 0x54, 0xf2, 0x8e, 0x9c, 0xc7, 0x21, 0xf9, 0x95, 0x27, 0xd6, 0x7, 0x4a, 0x1c, 0xc0, 0x5f, 0x6b, 0x2a, 0xc6, 0x65, 0xa4, 0xea, 0xe1, 0xb2, 0x2e, 0xd3, 0xa0, 0x4c, 0x19, 0xe5, 0x27, 0xef, 0x52, 0x4a, 0x44, 0x2a, 0x39, 0x3f, 0x50, 0xf7, 0xb6, 0x3e, 0xb5, 0x6e, 0xc1, 0x13, 0x9f, 0xe3, 0xe0, 0xf8, 0x17, 0xf0, 0xf5, 0xbe, 0x84, 0xf7, 0xf7, 0x56, 0xfd, 0x8d, 0x8c, 0x8e, 0xfc, 0xf4, 0xdb, 0x25, 0x2f, 0x1d, 0xb9, 0x93, 0x98, 0x60, 0xc2, 0x6a, 0x60, 0xcd, 0x33, 0x14, 0xbf, 0xd4, 0xea, 0x4a, 0xdf, 0x6c, 0xaf, 0xd5, 0xd6, 0x69, 0x90, 0xfd, 0x6a, 0xa3, 0xc5, 0xc7, 0x3e, 0x4e, 0x6e, 0xd0, 0x68, 0xa6, 0xb9, 0x4a, 0x50, 0xf3, 0x79, 0x39, 0x68, 0x22, 0xa8, 0xcc, 0x55, 0x49, 0x79, 0xd1, 0x3e, 0xe7, 0xb1, 0xf6, 0xfd, 0xaf, 0x6f, 0x25, 0xd5, 0xbc, 0x6, 0xdc, 0x4, 0xa7, 0x11, 0x75, 0xd1, 0xbf, 0x34, 0x92, 0x66, 0xa9, 0xdf, 0x7d, 0xdd, 0x5a, 0x1a, 0xa3, 0x53, 0x6f, 0xf8, 0x48, 0xb1, 0xdc, 0xe2, 0x40, 0x48, 0x13, 0xb0, 0x1b, 0xc5, 0x92, 0x52, 0x7a, 0xea, 0xcf, 0x25, 0xff, 0x8b, 0x21, 0xaf, 0xf4, 0x56, 0xbe, 0x4, 0x7c, 0x6a, 0xca, 0xd, 0xb3, 0x79, 0xf6, 0xce, 0x2c, 0x1c, 0xbc, 0x77, 0xfe, 0x2a, 0xe6, 0x72, 0xd1, 0xa6, 0xd9, 0xb3, 0xfa, 0x64, 0x2a, 0x5a, 0xb4, 0xb5, 0xea, 0x7a, 0x9b, 0xd3, 0x38, 0x64, 0x1b, 0x35, 0x98, 0x1f, 0xa9, 0x2e, 0x5a, 0x68, 0xa8, 0xa9, 0x9a, 0x83, 0x8d, 0xa4, 0xca, 0x4f, 0xf4, 0xa2, 0xfb, 0xdd, 0xb0, 0xff, 0xc2, 0x18, 0xfb, 0xe9, 0xfd, 0xa8, 0x40, 0xc2, 0x27, 0x4c, 0x89, 0x73, 0x17, 0x4, 0x25, 0x18, 0x3c, 0x3e, 0x3a, 0xe9, 0xe0, 0xa3, 0x64, 0x28, 0xe6, 0x37, 0x5e, 0x99, 0xe8, 0xc1, 0xd6, 0x67, 0xd, 0x9e, 0xd2, 0x48, 0x3c, 0x98, 0x47, 0x60, 0xac, 0x3d, 0x47, 0x38, 0x35, 0xa9, 0x8a, 0xd8, 0xaa, 0xc4, 0xf7, 0x6e, 0x77, 0x61, 0xe9, 0x81, 0x15, 0x3f, 0xbc, 0x77, 0x6a, 0x4e, 0x6e, 0xa7, 0x7f, 0x1, 0x58, 0x6f, 0xef, 0xa6, 0x27, 0x95, 0xea, 0x9f, 0xe3, 0x47, 0xb4, 0xb0, 0xad, 0xbc, 0x38, 0x6b, 0x9f, 0x3, 0x6b, 0xd2, 0x3a, 0xd6, 0x52, 0x58, 0xe2, 0xa9, 0xb0, 0x27, 0x73, 0xad, 0x8e, 0x2f, 0x25, 0x94, 0x61, 0x6a, 0x73, 0x19, 0xbb, 0xcc, 0xb3, 0x86, 0x21, 0x35, 0xf6, 0xbf, 0xf4, 0x82, 0x60, 0x16, 0x2b, 0x55, 0x67, 0x36, 0xb7, 0x42, 0xed, 0xed, 0x29, 0xc1, 0xda, 0x89, 0xac, 0xf3, 0xbb, 0xf1, 0xc0, 0xec, 0x61, 0x2c, 0xee, 0x7c, 0xf1, 0x9, 0x1c, 0xdf, 0xc9, 0xe9, 0xea, 0x9a, 0x4c, 0x39, 0xab, 0xf7, 0x38, 0xda, 0xf5, 0x88, 0xa, 0xfb, 0xe2, 0x84, 0xe8, 0xb8, 0x28, 0x4, 0xdc, 0xd2, 0x16, 0xe2, 0x7c, 0x62, 0x61, 0x57, 0xe, 0x35, 0x8a, 0xf8, 0xf4, 0xe1, 0xc6, 0xe9, 0x6d, 0x2e, 0xa7, 0x5b, 0xd2, 0x4f, 0x79, 0x82, 0x10, 0x8f, 0xa9, 0xda, 0xcb, 0x28, 0x5, 0x87, 0xf9, 0xd, 0xe, 0x2d, 0xe6, 0xae, 0x74, 0x80, 0xa7, 0x34, 0x1f, 0xcb, 0xec, 0xa1, 0x80, 0x96, 0x65, 0x3d, 0xf2, 0xfb, 0xd8, 0x14, 0x7c, 0xf0, 0xa4, 0x16, 0xf, 0x54, 0x4, 0x2e, 0x5c, 0xdb, 0xe2, 0x20, 0x12, 0x81, 0x7d, 0xd2, 0x50, 0x10, 0xb4, 0xde, 0x2f, 0x8, 0x9f, 0x78, 0x33, 0xa7, 0xed, 0xd, 0xd6, 0x92, 0x47, 0xcc, 0x49, 0xac, 0x9e, 0xf6, 0x17, 0x3a, 0xe8, 0xba, 0xca, 0xfb, 0x17, 0xb2, 0x97, 0xec, 0x72, 0x67, 0x5b, 0x76, 0x3, 0x67, 0xc1, 0xcc, 0x40, 0xad, 0xcd, 0x83, 0x92, 0x8d, 0xf, 0xc5, 0xf6, 0xd0, 0x23, 0x41, 0x7c, 0x92, 0xfd, 0x51, 0xd7, 0x90, 0xae, 0x9b, 0x6d, 0x3e, 0x7b, 0xa5, 0x1, 0xb3, 0x24, 0x8f, 0x75, 0x77, 0x23, 0xae, 0x5a, 0x50, 0xa2, 0xf3, 0x5, 0xf8, 0x80, 0x3e, 0x5a, 0x1e, 0x6a, 0xb0, 0x1f, 0x6f, 0x96, 0xc3, 0x30, 0xe8, 0x79, 0x58, 0xde, 0x4f, 0x1a, 0x30, 0xae, 0xd4, 0x59, 0xa, 0x60, 0x81, 0xb7, 0x87, 0xbc, 0xf6, 0xeb, 0x4f, 0x25, 0x4b, 0xe3, 0x12, 0xe, 0xfd, 0x51, 0xa1, 0xbd, 0x45, 0x2d, 0x49, 0x62, 0x39, 0x44, 0x55, 0xc2, 0x4e, 0xc3, 0xc1, 0x4c, 0x37, 0xda, 0xd4, 0xc1, 0x50, 0xe3, 0x45, 0xf0, 0x64, 0x11, 0x7a, 0x87, 0x60, 0x3f, 0xa1, 0x1, 0x6c, 0x71, 0xc5, 0x74, 0xd, 0x12, 0x9c, 0x3b, 0x7b, 0x7f, 0x5e, 0xe5, 0x36, 0xae, 0x2d, 0xd0, 0x1c, 0xbf, 0x51, 0xf6, 0x8e, 0x28, 0xec, 0x2d, 0xeb, 0x5c, 0x7f, 0x16, 0x49, 0xf9, 0x4b, 0x75, 0xbf, 0x50, 0xad, 0xed, 0x10, 0xb7, 0x1c, 0xd6, 0x57, 0x95, 0x2d, 0x68, 0xc2, 0xf, 0xa5, 0x9d, 0xb8, 0xbc, 0x79, 0x8d, 0x8b, 0x59, 0xa, 0x8d, 0x8c, 0x20, 0x42, 0xe3, 0xae, 0xce, 0x34, 0xf6, 0xb1, 0x3e, 0x66, 0x14, 0xa2, 0x31, 0xcf, 0x5c, 0xab, 0xbf, 0x0, 0xa6, 0x20, 0xfb, 0x6f, 0xb3, 0x65, 0xf1, 0x96, 0x20, 0xf, 0x64, 0xe7, 0x3f, 0x2b, 0x9e, 0x19, 0x84, 0x7a, 0x2, 0xd2, 0xf9, 0x91, 0x71, 0xba, 0x58, 0x1c, 0xc0, 0x60, 0x16, 0x53, 0x96, 0xad, 0xc4, 0x19, 0x36, 0xc6, 0x59, 0x9d, 0xd7, 0xea, 0x64, 0x6d, 0xd2, 0x44, 0x8d, 0x66, 0x43, 0x9c, 0xe0, 0x43, 0xf1, 0xd2, 0xe4, 0x12, 0xb3, 0x92, 0x3c, 0xbf, 0x23, 0x5, 0xcc, 0xb9, 0x45, 0x17, 0xe4, 0x2, 0x73, 0x10, 0x89, 0x5, 0x83, 0x46, 0x97, 0x9, 0xdd, 0x7e, 0xe0, 0x20, 0xfd, 0xf3, 0x3c, 0xf, 0xca, 0x61, 0x38, 0xb7, 0xe9, 0xec, 0x83, 0x4c, 0xf7, 0xbd, 0xfa, 0x3c, 0x9f, 0x7c, 0x6c, 0x7e, 0x86, 0x47, 0x91, 0x3f, 0x9d, 0xb5, 0xa8, 0xd9, 0xe0, 0x1f, 0x29, 0xf9, 0xd3, 0x57, 0x5c, 0xd5, 0x48, 0xf5, 0xd1, 0x41, 0xa2, 0x22, 0xcb, 0x7e, 0x1c, 0x65, 0xf1, 0x4f, 0xa6, 0x17, 0xd2, 0x97, 0xc8, 0xd4, 0xd6, 0xf6, 0x6c, 0x1, 0x44, 0xdd, 0x58, 0xdb, 0x8d, 0x9e, 0x1b, 0x54, 0xc9, 0x5e, 0x37, 0x42, 0xd8, 0xca, 0xa5, 0xb0, 0x66, 0x6d, 0x6d, 0xbb, 0x12, 0x3c, 0x2, 0x5d, 0xc, 0x63, 0xea, 0xd9, 0x29, 0xd1, 0xf7, 0x84, 0x29, 0xf, 0xe6, 0x93, 0x84, 0x4, 0xb, 0x79, 0xcc, 0x8a, 0x2f, 0xe3, 0x46, 0x7e, 0xe2, 0x52, 0x93, 0xde, 0xac, 0xeb, 0x3c, 0x17, 0xd1, 0x23, 0xa8, 0xe8, 0x81, 0x21, 0x20, 0xe1, 0xb6, 0x70, 0xf4, 0x51, 0x7e, 0x7e, 0x4b, 0xa6, 0xe2, 0x8f, 0x90, 0x1, 0xb4, 0xfb, 0xbd, 0x5b, 0x5a, 0x79, 0x4, 0x2a, 0x6d, 0xaf, 0xe5, 0xf9, 0x2e, 0xef, 0x62, 0xc5, 0x56, 0x5c, 0x38, 0x99, 0x5c, 0xa1, 0x6d, 0x55, 0xfa, 0x4c, 0x2d, 0x11, 0x66, 0xbb, 0x42, 0x6f, 0xb4, 0x12, 0x94, 0x9d, 0x5, 0x24, 0xcd, 0x5, 0x89, 0xd3, 0xa1, 0xd8, 0x17, 0x7a, 0xa0, 0x3, 0x41, 0x7e, 0xd4, 0x2b, 0x95, 0xd, 0x5b, 0x7e, 0x3a, 0xea, 0x58, 0xad, 0xbb, 0x74, 0xab, 0x34, 0x8f, 0xd6, 0xde, 0x5b, 0xf1, 0x56, 0xac, 0x1d, 0xba, 0xc1, 0xbd, 0x36, 0xf5, 0x64, 0x1a, 0xfd, 0x1f, 0xbd, 0x8f, 0x59, 0x35, 0xc, 0x6d, 0xdb, 0x5, 0xf8, 0x39, 0xe8, 0x73, 0xc8, 0x27, 0xd4, 0xfd, 0x46, 0xa6, 0xad, 0xf0, 0xb8, 0x4e, 0x43, 0x29, 0xd1, 0x2, 0x90, 0x86, 0x50, 0xaf, 0x93, 0x58, 0x85, 0x5b, 0x79, 0xe2, 0x94, 0x9e, 0x5f, 0x41, 0x24, 0x9c, 0xa6, 0xfa, 0xfd, 0x6d, 0xd2, 0xce, 0x3, 0x14, 0x4, 0xd9, 0x8b, 0x5c, 0xc2, 0xa6, 0x2c, 0x60, 0x26, 0xc8, 0x28, 0xf4, 0x7d, 0x2b, 0xbe, 0x9d, 0xb1, 0x81, 0x7e, 0x67, 0x55, 0x63, 0x4, 0x77, 0x0, 0xb7, 0x53, 0x5, 0x2e, 0x99, 0xf0, 0xae, 0x3f, 0x3b, 0x5e, 0xd3, 0xad, 0xc1, 0x3d, 0x81, 0x2f, 0x7c, 0x16, 0x23, 0x3a, 0xbe, 0x81, 0xbb, 0x3e, 0xce, 0x12, 0xd5, 0x11, 0xaf, 0xc4, 0x5a, 0x29, 0xb6, 0xe6, 0xb8, 0x8, 0xe9, 0x1f, 0x76, 0x6e, 0x7d, 0xbd, 0x29, 0xea, 0x78, 0x2, 0x15, 0x83, 0x55, 0xa2, 0x95, 0xa3, 0x9, 0x90, 0x68, 0x9b, 0xad, 0x78, 0x41, 0xae, 0x27, 0xad, 0xbc, 0x74, 0xbe, 0xb1, 0x17, 0xf9, 0x74, 0x64, 0x8d, 0xed, 0x53, 0x51, 0xb6, 0x5a, 0x71, 0x99, 0x6a, 0xf1, 0xf, 0x2, 0xfe, 0xa4, 0x69, 0x98, 0xe7, 0xb0, 0x7c, 0xd0, 0xbd, 0x2e, 0x45, 0xc2, 0x37, 0x76, 0x38, 0xa6, 0x3e, 0xd5, 0x6d, 0xc8, 0xf2, 0x99, 0x88, 0xe0, 0x43, 0xf8, 0xb5, 0xc2, 0xf5, 0x48, 0x55, 0x79, 0xc3, 0x1a, 0xca, 0x1e, 0x4c, 0x13, 0x7e, 0xce, 0x29, 0x5f, 0x6a, 0xea, 0x67, 0x46, 0xc1, 0xc6, 0xfa, 0xf4, 0x96, 0xf0, 0xa0, 0xe0, 0x57, 0x53, 0x6f, 0x5c, 0x90, 0x87, 0xfa, 0x85, 0xd2, 0xcf, 0xea, 0xc0, 0xb2, 0x92, 0x50, 0x8a, 0x74, 0x69, 0xdf, 0xfb, 0xa5, 0x4f, 0x81, 0xe, 0x56, 0xbf, 0x96, 0x94, 0x3a, 0x2d, 0x2, 0x4, 0x35, 0xa, 0x16, 0xf7, 0x60, 0xcd, 0x4f, 0x5e, 0xb2, 0x21, 0x8e, 0xf0, 0xe6, 0x83, 0x46, 0x12, 0xe7, 0xb4, 0x75, 0x0, 0xb8, 0x2f, 0xf, 0xdd, 0xea, 0x32, 0x6a, 0x23, 0x56, 0x17, 0x70, 0x5d, 0x2b, 0xec, 0x32, 0xe2, 0xc8, 0xcc, 0xd0, 0xf0, 0x37, 0xbc, 0xa, 0x71, 0x51, 0xa5, 0x32, 0x31, 0x84, 0x41, 0x21, 0x11, 0x47, 0xac, 0xe2, 0x44, 0x4d, 0xdd, 0xf7, 0x51, 0x54, 0x6a, 0x16, 0x6b, 0x21, 0x3f, 0xd2, 0x4f, 0x7, 0x3a, 0x64, 0xce, 0xd8, 0xcd, 0x45, 0x51, 0xf, 0x12, 0xa4, 0x5b, 0x93, 0x81, 0x61, 0xb6, 0xf8, 0xad, 0x18, 0x1d, 0xde, 0x69, 0x9b, 0xcb, 0xbb, 0x7, 0xa8, 0x4f, 0x82, 0x24, 0xcc, 0x1e, 0xb3, 0xfc, 0x5e, 0xa8, 0xe4, 0x5f, 0x63, 0x81, 0x9f, 0x6a, 0xd4, 0xfc, 0x55, 0x13, 0x9b, 0xb, 0x73, 0x25, 0x34, 0xbb, 0x6f, 0xe4, 0x19, 0x2, 0x6, 0x28, 0xd2, 0x5f, 0x1b, 0xe4, 0x54, 0xee, 0x76, 0xe7, 0x40, 0x5a, 0xb1, 0x5b, 0xec, 0xdc, 0x9a, 0xef, 0x79, 0x5d, 0x3c, 0xa2, 0xa9, 0x73, 0x71, 0x1d, 0x25, 0x4e, 0x62, 0xe7, 0xad, 0x2b, 0x42, 0x76, 0xd5, 0x50, 0xd5, 0xc3, 0xe9, 0xb1, 0x6f, 0x42, 0xf1, 0x92, 0x12, 0xed, 0x4e, 0xc5, 0x47, 0x7f, 0xf6, 0xa1, 0xa7, 0xc, 0x14, 0xd2, 0x2a, 0xc6, 0x1e, 0x7a, 0x80, 0xfa, 0x4a, 0x4b, 0x49, 0x9f, 0x68, 0x31, 0x84, 0x1, 0xd8, 0x7c, 0x2b, 0xec, 0xf2, 0x53, 0xa8, 0x89, 0xb5, 0xfb, 0xe, 0xfb, 0x5, 0x3e, 0x24, 0x7, 0x19, 0xee, 0xa, 0xfa, 0x8a, 0x62, 0x2c, 0x4a, 0xdb, 0xfb, 0x11, 0xcb, 0x86, 0x31, 0xc4, 0xfe, 0x53, 0xc8, 0x6d, 0xf6, 0xf3, 0x2e, 0x92, 0xe0, 0xcc, 0xc9, 0xeb, 0x58, 0x14, 0xda, 0x4f, 0x39, 0xa1, 0x97, 0x77, 0xd6, 0xbf, 0xf0, 0x65, 0x4c, 0x4, 0xd4, 0x70, 0x48, 0x6e, 0xbc, 0x7b, 0xcd, 0x75, 0xe, 0x4b, 0x6d, 0xf4, 0x20, 0xda, 0x9f, 0xcd, 0xb3, 0x88, 0xb9, 0xbf, 0xb0, 0xdc, 0xde, 0xd6, 0x12, 0xfb, 0x1c, 0x57, 0xe1, 0x18, 0xf7, 0xe8, 0x39, 0xfe, 0x8, 0x9, 0x58, 0xb2, 0x1d, 0xcf, 0xf9, 0x91, 0x91, 0xc5, 0x74, 0x6b, 0x1c, 0xb6, 0xdb, 0xae, 0xd0, 0x6f, 0x15, 0x54, 0x6e, 0xfd, 0xca, 0x11, 0xb5, 0xdb, 0xc1, 0xd1, 0x1b, 0x78, 0x3e, 0x6d, 0x3d, 0x3e, 0x9a, 0xc6, 0xf8, 0x77, 0x8, 0xc0, 0x4, 0x84, 0x3, 0x20, 0x0, 0xe0, 0xe1, 0xe1, 0x90, 0xfe, 0xf7, 0xfb, 0x27, 0x1c, 0x0, 0x97, 0x96, 0x47, 0x4a, 0xd3, 0x1c, 0x2, 0xc, 0x49, 0x29, 0x6e, 0xea, 0xdf, 0xbb, 0x9d, 0xbf, 0xfb, 0xdf, 0xaf, 0x83, 0xef, 0x81, 0xe5, 0x97, 0x58, 0x25, 0x64, 0x7f, 0x1, 0x74, 0x42, 0x41, 0x31, 0xef, 0xe7, 0x98, 0xff, 0x2, 0xf0, 0xdc, 0x35, 0x7e, 0x7d, 0x50, 0xb9, 0x7b, 0xff, 0x3, 0x77, 0x23, 0x29, 0x36, 0xac, 0xef, 0x1d, 0xaa, 0x4, 0x75, 0xf4, 0x4a, 0xe8, 0x7e, 0x2, 0xd1, 0xa, 0x1c, 0xfa, 0xc0, 0x34, 0xd0, 0x82, 0x3, 0xf5, 0x95, 0x57, 0x6b, 0x94, 0x17, 0x21, 0x8e, 0xe5, 0x1b, 0x38, 0xda, 0x82, 0x30, 0xac, 0x6f, 0x97, 0xb, 0x57, 0x84, 0x30, 0xd9, 0x2, 0x30, 0x1a, 0x99, 0x85, 0x2e, 0x8d, 0xed, 0x16, 0xc1, 0xbe, 0xa0, 0x11, 0xfc, 0xe7, 0x31, 0x9, 0x23, 0x0, 0xff, 0x37, 0x2e, 0x90, 0xd8, 0x75, 0xc0, 0xbb, 0x30, 0x1, 0x3e, 0x28, 0x82, 0x23, 0x28, 0x3a, 0xeb, 0xf3, 0x36, 0x5a, 0x42, 0x60, 0xfa, 0x52, 0xd6, 0xfa, 0x27, 0xe4, 0xdf, 0xb8, 0x7f, 0x1, 0xb2, 0xa, 0xbf, 0x79, 0xb0, 0x6d, 0xf7, 0xb, 0x5f, 0x63, 0xc1, 0xff, 0x8e, 0xf5, 0xfc, 0x53, 0xa2, 0x15, 0x94, 0x22, 0x32, 0xff, 0x11, 0xff, 0xb5, 0x96, 0xb9, 0xa8, 0x17, 0xe8, 0xf8, 0x5b, 0x56, 0x7f, 0xfa, 0x8e, 0xfa, 0x51, 0x96, 0x1c, 0xf6, 0x2d, 0x25, 0x43, 0x68, 0x8c, 0x8b, 0xc1, 0x1e, 0xdd, 0x1c, 0x51, 0x54, 0xfb, 0x57, 0x8e, 0xeb, 0x90, 0x9d, 0x55, 0xb, 0x51, 0xc0, 0x67, 0xba, 0xea, 0xd8, 0x6b, 0xa2, 0x38, 0x17, 0xdb, 0x65, 0x2f, 0xb8, 0x89, 0xb7, 0xa8, 0x77, 0x47, 0x9, 0x39, 0x69, 0x92, 0xf0, 0x1f, 0x11, 0x3b, 0xda, 0xed, 0xdc, 0xf0, 0x26, 0x8a, 0xcb, 0xb3, 0xfb, 0xaa, 0xe1, 0x3b, 0x87, 0x5a, 0xd5, 0x7a, 0x68, 0x5c, 0x7e, 0x19, 0x1e, 0x13, 0xcc, 0x48, 0xd7, 0x97, 0xff, 0x71, 0x97, 0xe3, 0x92, 0x79, 0xfa, 0x74, 0x3f, 0xea, 0x16, 0x4e, 0x84, 0xb1, 0x25, 0x63, 0x45, 0x21, 0xd9, 0x49, 0x54, 0x5c, 0x93, 0xe7, 0x5f, 0x98, 0x2a, 0xf6, 0x11, 0x3f, 0xfc, 0x6e, 0x93, 0x64, 0x72, 0xd5, 0xe3, 0xb4, 0x5d, 0x55, 0x57, 0xe7, 0x52, 0xca, 0x6d, 0x2a, 0xcb, 0xa2, 0xb9, 0x47, 0x26, 0x55, 0x4b, 0x4c, 0xbd, 0xb4, 0xa6, 0xce, 0xd2, 0xad, 0x53, 0x2b, 0x5f, 0x1c, 0x54, 0x49, 0x61, 0x55, 0x83, 0x72, 0x43, 0x7e, 0x47, 0xa4, 0x9c, 0xde, 0xc8, 0x9a, 0xf5, 0x68, 0x1c, 0x8e, 0xc9, 0x74, 0x3f, 0x1e, 0xa6, 0xc0, 0xef, 0xc3, 0xc0, 0xa5, 0xee, 0xfd, 0x8b, 0x54, 0xd0, 0x13, 0x35, 0x9f, 0x5e, 0xa3, 0x17, 0xbd, 0x30, 0x87, 0xb0, 0x2, 0xe4, 0xe6, 0x80, 0x4d, 0xdb, 0x25, 0x13, 0x1c, 0xca, 0x51, 0x1d, 0xbc, 0x2f, 0x83, 0x84, 0x5c, 0x20, 0x4d, 0xbe, 0xa9, 0x59, 0x71, 0x3d, 0x32, 0xfd, 0xa, 0x59, 0xce, 0x3f, 0x47, 0xdc, 0x93, 0xe9, 0x8e, 0xc3, 0xd5, 0x38, 0x37, 0x74, 0x93, 0x4f, 0x89, 0x54, 0x52, 0x22, 0x43, 0xe1, 0xbd, 0xb8, 0xce, 0xa7, 0xdb, 0x8a, 0xa4, 0xa0, 0x2d, 0x4e, 0x12, 0x54, 0x65, 0x3f, 0xb5, 0x45, 0x73, 0x91, 0x90, 0x7e, 0xf5, 0x8f, 0xfd, 0xde, 0x2c, 0x8, 0x7, 0x7f, 0x8d, 0xd2, 0x5f, 0xda, 0x81, 0xdd, 0x1d, 0xe5, 0xda, 0xb1, 0xd5, 0xe6, 0xc1, 0x8d, 0x8d, 0x6e, 0x41, 0x3d, 0x8e, 0x9e, 0x4c, 0x3f, 0x18, 0x23, 0xfb, 0x35, 0xc8, 0x4e, 0x68, 0xe8, 0x84, 0xe4, 0xfd, 0x26, 0x97, 0xb6, 0xa9, 0xf5, 0x90, 0xe1, 0xaa, 0x51, 0x64, 0x52, 0xce, 0xd7, 0x2e, 0xe, 0x62, 0x1a, 0xb4, 0x41, 0x43, 0xfb, 0x8c, 0xf4, 0xeb, 0xf4, 0x3e, 0x78, 0x3d, 0xba, 0x1f, 0xb9, 0x3a, 0xaa, 0x1f, 0x30, 0xb, 0xc2, 0xe7, 0x79, 0x65, 0xb8, 0xbd, 0xa2, 0xf0, 0x70, 0x1b, 0x8b, 0x1d, 0x3a, 0xa5, 0x55, 0x30, 0x3c, 0x8d, 0x4, 0xb0, 0x3a, 0x6b, 0xec, 0xb6, 0xd5, 0xcb, 0x88, 0x76, 0x48, 0xe5, 0x2c, 0xd5, 0x2a, 0x75, 0xe2, 0x3, 0xe3, 0x47, 0xe9, 0xa3, 0x7f, 0xb0, 0xce, 0x7, 0x13, 0x3e, 0x3f, 0x16, 0x23, 0x3, 0xd8, 0x2b, 0xe6, 0x98, 0x1f, 0xf1, 0x84, 0xd1, 0x70, 0x4b, 0x40, 0xa2, 0x99, 0x85, 0x72, 0x64, 0x32, 0xa4, 0xc2, 0x26, 0xc, 0x16, 0x23, 0xe3, 0x31, 0xb8, 0xdb, 0xe5, 0xd5, 0x5f, 0x3d, 0x7f, 0x50, 0xfd, 0x99, 0x2f, 0x5, 0xf, 0x7b, 0xaa, 0xba, 0x1d, 0xd3, 0x37, 0x94, 0x92, 0xba, 0xb0, 0xd7, 0xef, 0x42, 0x26, 0x39, 0x5d, 0x65, 0xc9, 0x2, 0xde, 0x27, 0x6f, 0x54, 0x68, 0x42, 0xf2, 0x69, 0xad, 0x1b, 0xe5, 0x55, 0x3e, 0x59, 0xdc, 0xf, 0x3e, 0xa6, 0xf3, 0x65, 0x9b, 0xe3, 0xd, 0x15, 0x5d, 0x21, 0x49, 0x47, 0xd0, 0x22, 0xa9, 0xc, 0x60, 0x92, 0x7, 0xc3, 0xf4, 0x23, 0xac, 0xdf, 0x59, 0x7e, 0xb0, 0x22, 0xcb, 0x83, 0x3b, 0x26, 0xd1, 0x21, 0x69, 0xec, 0x60, 0xb8, 0x88, 0xac, 0xcd, 0xc7, 0xbc, 0x1d, 0xd6, 0x81, 0xb3, 0x9e, 0x84, 0x96, 0x4f, 0xbe, 0x49, 0x73, 0x6a, 0x68, 0x76, 0x80, 0xca, 0x10, 0x3c, 0x97, 0x8f, 0x91, 0xce, 0xd5, 0x7a, 0xa5, 0xfb, 0x73, 0x6d, 0x95, 0xf9, 0xfc, 0x52, 0x9, 0x2b, 0x18, 0xae, 0xeb, 0x4, 0xe1, 0xfb, 0x44, 0x96, 0xde, 0x27, 0xf4, 0xc9, 0xf8, 0x2a, 0x0, 0x9a, 0x99, 0x7f, 0x26, 0xe3, 0xaa, 0x65, 0x33, 0xb3, 0x36, 0x21, 0xb9, 0x5d, 0xfb, 0x2, 0x41, 0x7f, 0xcc, 0xb4, 0xc, 0x47, 0x24, 0xcd, 0x8f, 0x3d, 0xc6, 0xe, 0x5e, 0xb2, 0xde, 0x87, 0x82, 0x12, 0xf7, 0x97, 0x2a, 0xf5, 0xbe, 0x9d, 0xf9, 0x2e, 0x71, 0x66, 0x8, 0x3e, 0x99, 0x4c, 0x76, 0x7e, 0x1d, 0x53, 0x4d, 0xf7, 0x43, 0x78, 0x15, 0x6a, 0xb6, 0x6, 0x72, 0x95, 0x33, 0xb2, 0xf1, 0x33, 0x6e, 0xfa, 0x50, 0x69, 0x76, 0x39, 0xab, 0x98, 0x8, 0xc3, 0xdd, 0xab, 0xec, 0x64, 0xac, 0xd2, 0x4d, 0x69, 0x5, 0x17, 0xd3, 0x71, 0x2a, 0xfa, 0x2, 0xf, 0x44, 0xd8, 0xd3, 0x82, 0x9b, 0xb5, 0xe8, 0x9d, 0xe, 0x65, 0xd0, 0xf8, 0x2c, 0x3d, 0x7, 0xc8, 0x40, 0xb8, 0x8b, 0x7a, 0x2c, 0xec, 0x8, 0xea, 0x5a, 0x73, 0x79, 0xda, 0xf0, 0x18, 0x16, 0x8a, 0x14, 0x6f, 0x60, 0xd2, 0x29, 0x6d, 0x12, 0x9d, 0xf5, 0x68, 0x46, 0x3, 0xb2, 0x8, 0x13, 0x35, 0x9b, 0x70, 0x14, 0x4, 0x3c, 0xc, 0x47, 0xe9, 0x33, 0x3c, 0xd4, 0x36, 0x5c, 0x75, 0x35, 0x3e, 0x82, 0xda, 0x87, 0xef, 0xac, 0xad, 0x0, 0xe7, 0x3, 0x56, 0x9a, 0x9e, 0x82, 0xb7, 0x64, 0xe4, 0x62, 0xdd, 0xf6, 0x14, 0x43, 0x61, 0x58, 0x57, 0x26, 0xce, 0xb9, 0xa1, 0x5c, 0xc2, 0x28, 0xac, 0x4, 0x8f, 0xf3, 0x8e, 0xf3, 0x3e, 0xf1, 0xf3, 0xbe, 0xe9, 0x90, 0xcf, 0x28, 0xc4, 0x75, 0xbf, 0xe4, 0xd4, 0x7c, 0x77, 0x69, 0x1f, 0xf9, 0xb9, 0x69, 0x8, 0xa1, 0x1d, 0xd3, 0xd9, 0xae, 0x0, 0x50, 0x17, 0x6d, 0xc0, 0xcd, 0x12, 0x27, 0x84, 0x1d, 0x32, 0x4d, 0x3d, 0xc6, 0x20, 0xa, 0x69, 0x9c, 0x1c, 0x8b, 0x36, 0xd3, 0xd5, 0x69, 0xce, 0xd0, 0x21, 0x6c, 0x82, 0x4e, 0x1f, 0xa6, 0xfa, 0x36, 0x7c, 0x52, 0xc, 0x2d, 0x43, 0x3e, 0x3e, 0x6f, 0x11, 0xbe, 0x72, 0x5d, 0xdf, 0xa7, 0x8f, 0x29, 0x89, 0xad, 0x48, 0x6, 0x70, 0x9b, 0x5c, 0x7f, 0xe6, 0xa4, 0x9a, 0x63, 0xb1, 0x3f, 0x1d, 0x8f, 0xa3, 0x1, 0x8, 0x90, 0xac, 0x21, 0x12, 0xc4, 0x56, 0x2b, 0x6a, 0x78, 0xf4, 0x3e, 0x79, 0x46, 0xf9, 0x6e, 0xe7, 0x5a, 0x25, 0x41, 0x4a, 0x26, 0x8b, 0x99, 0x12, 0x9a, 0x99, 0x3b, 0x68, 0xf3, 0x83, 0xee, 0x42, 0x83, 0xf, 0x39, 0x14, 0x79, 0x43, 0x98, 0x74, 0x95, 0x85, 0x99, 0x7b, 0x50, 0xf2, 0x1f, 0xe9, 0x89, 0x9e, 0x96, 0x88, 0xe3, 0x98, 0xbe, 0x5c, 0xad, 0x0, 0x18, 0xf1, 0xd0, 0x94, 0xab, 0x8e, 0xfd, 0x7f, 0x45, 0x62, 0x73, 0x67, 0xa7, 0x8a, 0xc7, 0x61, 0x24, 0x6e, 0x70, 0x70, 0x11, 0x88, 0xb1, 0x1d, 0xa4, 0xd3, 0x3e, 0xab, 0xe8, 0xf5, 0xf9, 0x2, 0x7b, 0x1a, 0x6d, 0xfa, 0xc4, 0xe5, 0xe7, 0xbd, 0x2, 0x66, 0xf7, 0xd8, 0xb9, 0xa5, 0x3d, 0x8b, 0x2a, 0xb1, 0xf2, 0xda, 0x11, 0xee, 0xde, 0xf, 0x15, 0xe1, 0x28, 0xdc, 0x93, 0x3c, 0x60, 0xc8, 0x68, 0x64, 0xe1, 0x2d, 0xef, 0x7f, 0x73, 0x5e, 0xd1, 0x9e, 0x4a, 0x3, 0x66, 0x8f, 0xaa, 0x30, 0x15, 0xe4, 0xc4, 0xc, 0x2d, 0xdb, 0x4c, 0xe2, 0xd2, 0x32, 0xa6, 0x5a, 0xa4, 0x46, 0xc8, 0xe3, 0xd6, 0x13, 0xac, 0x50, 0x29, 0x76, 0x59, 0x12, 0xc4, 0xb5, 0x68, 0xc5, 0xe5, 0x32, 0x3, 0x97, 0xad, 0xb6, 0x67, 0x19, 0x8e, 0xc, 0x2a, 0x55, 0x6c, 0x99, 0x4a, 0xfc, 0xc, 0x48, 0x3b, 0x7, 0x22, 0xab, 0x8, 0x48, 0xe9, 0x90, 0x13, 0x13, 0xea, 0x45, 0x9a, 0x52, 0x75, 0xdd, 0x6c, 0x14, 0x10, 0x91, 0xa4, 0x83, 0x6b, 0xb9, 0xd2, 0x51, 0x27, 0xba, 0x54, 0x5d, 0xe, 0x74, 0xec, 0x1a, 0xda, 0x35, 0x83, 0xe7, 0xd8, 0x26, 0xa5, 0xc, 0xe, 0xec, 0x6a, 0x63, 0x91, 0xc6, 0xfb, 0x2f, 0x64, 0x99, 0x76, 0xe7, 0xd7, 0x51, 0x69, 0x36, 0xb3, 0xe3, 0xd9, 0xaf, 0x45, 0xb4, 0x51, 0x86, 0x60, 0x3, 0x5d, 0x55, 0xfe, 0x65, 0x6e, 0xc0, 0x9a, 0xb5, 0x36, 0x15, 0x98, 0xf3, 0xef, 0x2d, 0x95, 0x75, 0x9, 0x5, 0x63, 0xb0, 0xca, 0x62, 0x3f, 0x72, 0x92, 0xb6, 0x40, 0x76, 0xe6, 0xa6, 0x3e, 0x6f, 0x1, 0xcb, 0xd9, 0xb5, 0x6e, 0x20, 0x2, 0x12, 0xd2, 0xa7, 0x77, 0x61, 0x86, 0x4e, 0xab, 0x9f, 0x8f, 0xe, 0x92, 0x1, 0x8c, 0x28, 0x3, 0x3, 0x1a, 0xfc, 0x18, 0xfb, 0xa1, 0xa6, 0x6b, 0xf1, 0x81, 0x26, 0x8d, 0x8f, 0xbb, 0xbb, 0xc5, 0xe8, 0x29, 0xe8, 0x8f, 0x69, 0xa2, 0xdb, 0x5a, 0xfb, 0x52, 0xda, 0x3f, 0xe9, 0x62, 0x28, 0x23, 0x66, 0x15, 0xad, 0x78, 0x59, 0x57, 0x3f, 0xa9, 0x7, 0x83, 0x88, 0x3e, 0x49, 0xf, 0x34, 0xcd, 0xf5, 0x2, 0x5f, 0x2a, 0xb3, 0x69, 0x65, 0x97, 0xda, 0xa2, 0xb9, 0xd, 0x6, 0x6, 0x12, 0xb, 0x32, 0xc3, 0xbe, 0x56, 0xc9, 0xa5, 0xc0, 0xd7, 0x5d, 0x11, 0x45, 0x1a, 0x96, 0x45, 0xe7, 0xd3, 0x20, 0xf0, 0x48, 0xa4, 0xe1, 0xd3, 0xd2, 0x89, 0xe1, 0x28, 0xcb, 0x9c, 0xad, 0x61, 0xb9, 0x96, 0x7c, 0x26, 0x9c, 0x4d, 0x73, 0x21, 0xc9, 0x16, 0x53, 0x2e, 0xcb, 0x2e, 0xca, 0x1f, 0x78, 0x87, 0xae, 0x48, 0xf0, 0x21, 0xe6, 0x70, 0xd5, 0xe4, 0x6e, 0x13, 0x81, 0xe9, 0xdb, 0xe8, 0x5c, 0x58, 0xf3, 0xc4, 0xa7, 0x73, 0xec, 0xe1, 0x60, 0xf6, 0xa3, 0xf4, 0xf, 0xb0, 0xba, 0x7, 0x91, 0x22, 0x8c, 0x9, 0x73, 0xc1, 0xec, 0xe0, 0x8f, 0xc0, 0x4c, 0xc3, 0x29, 0xee, 0x9b, 0x9c, 0x4b, 0x1f, 0x2c, 0xb6, 0xdb, 0x90, 0xa4, 0x50, 0xb, 0x7d, 0xe2, 0x64, 0x63, 0x20, 0x3e, 0x87, 0xca, 0x2e, 0xa1, 0xd6, 0x2d, 0x7e, 0x74, 0xf7, 0x1a, 0xac, 0x91, 0x46, 0x3c, 0xbc, 0xc6, 0xe4, 0x24, 0x73, 0x33, 0x44, 0xa6, 0xac, 0xee, 0x92, 0x36, 0x41, 0xad, 0x99, 0x2d, 0xde, 0x40, 0xc5, 0x52, 0x6a, 0x98, 0xa5, 0x12, 0x75, 0xe4, 0xb1, 0x36, 0xac, 0xae, 0xf7, 0xf7, 0xe, 0x89, 0xf4, 0x6, 0x37, 0x1b, 0x2c, 0xab, 0x4d, 0x59, 0x75, 0x17, 0x54, 0x44, 0xa6, 0xcb, 0xcc, 0xa3, 0x1d, 0x0, 0x53, 0xb6, 0xa8, 0xb5, 0xd8, 0xe7, 0x52, 0x69, 0xc5, 0xab, 0xed, 0xda, 0x27, 0xea, 0x22, 0x6b, 0x47, 0x1e, 0x9b, 0xa7, 0xc3, 0x6a, 0xe3, 0x33, 0x4a, 0xa0, 0xd2, 0x9c, 0x67, 0x2f, 0x6e, 0xdc, 0xa8, 0x45, 0xd3, 0xee, 0xfb, 0x54, 0x5, 0x6a, 0x9d, 0x8e, 0x60, 0x59, 0x43, 0x8b, 0x65, 0xb4, 0x27, 0x43, 0xeb, 0xc7, 0x7c, 0x61, 0x3b, 0xa9, 0x86, 0x63, 0x41, 0x7d, 0xfe, 0x35, 0x18, 0x89, 0x76, 0x4c, 0xcb, 0x2a, 0x44, 0xf2, 0x9d, 0x5, 0x35, 0xd0, 0x5a, 0x89, 0xf7, 0x6d, 0xdf, 0xc7, 0x37, 0x4b, 0x0, 0x8e, 0x11, 0xd9, 0x3, 0x6e, 0x76, 0xca, 0x53, 0x8c, 0x83, 0x2d, 0x8b, 0x65, 0xbd, 0x9a, 0x62, 0x50, 0x66, 0x37, 0xdb, 0xc5, 0x61, 0xa2, 0x59, 0x48, 0x16, 0x51, 0x24, 0x4b, 0xdc, 0xf2, 0xa3, 0xce, 0xe1, 0x2e, 0x12, 0x69, 0xeb, 0x33, 0xfc, 0x2d, 0xfe, 0x40, 0xbf, 0x0, 0xb7, 0xd5, 0x4e, 0x65, 0x98, 0x25, 0x89, 0xb6, 0x9f, 0x60, 0x30, 0x40, 0x63, 0x5b, 0x15, 0xe3, 0xc8, 0x1e, 0x21, 0xc0, 0x6c, 0x1, 0xfb, 0x86, 0x3d, 0xb8, 0x82, 0x85, 0x68, 0x2e, 0x75, 0x76, 0x8f, 0xc, 0x5e, 0xab, 0xea, 0xb9, 0xa2, 0x49, 0xf8, 0xdb, 0x4b, 0x97, 0x6b, 0x60, 0x3c, 0xd4, 0xb7, 0x74, 0xbe, 0x4c, 0x8, 0x11, 0xa9, 0x16, 0x1b, 0x9d, 0x17, 0x23, 0x23, 0x9c, 0xdf, 0x95, 0xa2, 0xa0, 0x42, 0x9c, 0x9c, 0x98, 0xb5, 0x9f, 0x31, 0xae, 0x6, 0x7, 0xb7, 0x8c, 0xe9, 0x1, 0x72, 0xde, 0x8f, 0xaf, 0x22, 0xa2, 0x4, 0x4d, 0x9a, 0x46, 0x4a, 0xc7, 0x3, 0x36, 0x4a, 0xf6, 0xdb, 0x59, 0x56, 0xe3, 0x78, 0x5a, 0xf0, 0xd5, 0x3, 0xd4, 0xa3, 0x6b, 0xb2, 0x95, 0xa3, 0x23, 0x4c, 0x8b, 0x3, 0x2a, 0x6f, 0xf3, 0xa5, 0x24, 0xb3, 0x41, 0x28, 0xc5, 0x80, 0xf4, 0x92, 0xcb, 0xe0, 0x4, 0x21, 0x99, 0x21, 0xa4, 0xf8, 0x73, 0x24, 0xd5, 0xf6, 0x18, 0xc9, 0x1b, 0x50, 0x4d, 0xf0, 0xe2, 0xb8, 0x66, 0x20, 0xc2, 0x2b, 0x56, 0x27, 0xaa, 0x22, 0x99, 0x43, 0x33, 0x4e, 0x1b, 0x8d, 0x0, 0x1b, 0x54, 0xb, 0xcc, 0x19, 0x99, 0xce, 0x7c, 0x92, 0x28, 0x24, 0xc2, 0xb4, 0x8f, 0x20, 0x1c, 0x3, 0x9a, 0xc9, 0xb3, 0xf3, 0xe6, 0x18, 0x33, 0x58, 0x5c, 0xe6, 0x66, 0x11, 0x96, 0xf8, 0x2, 0x1a, 0x1a, 0xf2, 0x4f, 0xb1, 0xcb, 0xc5, 0x6b, 0x90, 0xb6, 0xe4, 0x1c, 0x8f, 0x67, 0x93, 0xb4, 0x77, 0xcb, 0x8d, 0x86, 0x43, 0x6, 0xd1, 0x2, 0xe5, 0x4a, 0x32, 0xad, 0xf1, 0xdb, 0xd6, 0xa2, 0x50, 0xd5, 0xc8, 0x52, 0x70, 0xd5, 0x69, 0xd7, 0xc7, 0xd0, 0x42, 0xa8, 0xdc, 0x39, 0x76, 0xed, 0x6b, 0xba, 0xe8, 0x5c, 0xec, 0x62, 0x6a, 0xc6, 0x2b, 0x69, 0xf9, 0xc5, 0x65, 0x2, 0x80, 0xeb, 0xcd, 0x4e, 0xed, 0x67, 0x9f, 0x69, 0xe9, 0x9d, 0x21, 0x1d, 0x95, 0x2e, 0x5, 0xd5, 0xb3, 0xac, 0x34, 0x70, 0x9b, 0x0, 0xc6, 0x9c, 0x99, 0x6f, 0x89, 0x88, 0xad, 0x95, 0x13, 0x45, 0xa1, 0x35, 0x16, 0xcf, 0x74, 0xd, 0x74, 0x5c, 0xbf, 0x54, 0xaa, 0xae, 0x8b, 0x9f, 0x48, 0x17, 0x37, 0x35, 0x2, 0x8c, 0xfc, 0x41, 0xdc, 0x2a, 0xd7, 0x58, 0xe4, 0xcd, 0x5f, 0x35, 0x38, 0xab, 0x42, 0xb4, 0x85, 0xbf, 0x43, 0x16, 0x7a, 0x71, 0x48, 0x85, 0xdf, 0xe1, 0x1c, 0xb6, 0x9c, 0xb1, 0x24, 0x49, 0xc, 0xb6, 0x24, 0x4e, 0x80, 0x18, 0xc2, 0x74, 0x8c, 0x94, 0xcd, 0xd2, 0x17, 0xa4, 0x5, 0xb9, 0xa3, 0x5, 0x89, 0xcc, 0x3e, 0x95, 0x54, 0x4d, 0x7, 0x13, 0xc3, 0x6, 0xbb, 0x4c, 0x10, 0x9c, 0x0, 0xdc, 0x9c, 0xb2, 0x3a, 0x1d, 0xfc, 0x27, 0x56, 0xfc, 0x21, 0xc1, 0x13, 0x98, 0xaa, 0x84, 0xfd, 0x65, 0x19, 0xd6, 0x51, 0x29, 0x8a, 0xd1, 0xe0, 0xce, 0xd6, 0x36, 0xda, 0x10, 0xd6, 0xee, 0x2d, 0xd8, 0x39, 0xdb, 0x22, 0x14, 0x4f, 0x4a, 0xd5, 0x19, 0x94, 0x1, 0x6a, 0x32, 0xfb, 0x80, 0x88, 0xd7, 0x9e, 0x65, 0x9c, 0x8b, 0x3f, 0x22, 0x5e, 0x44, 0xc, 0x47, 0x50, 0x23, 0xe2, 0xd0, 0xea, 0xe4, 0x1d, 0xd7, 0xb, 0x94, 0xe4, 0x1, 0x11, 0x15, 0x85, 0xd9, 0xd0, 0x45, 0xe, 0x31, 0x64, 0xcf, 0xbf, 0x21, 0x8a, 0xa2, 0xf5, 0x9, 0xb1, 0x81, 0xc, 0x8d, 0x9b, 0xb, 0xfa, 0xde, 0xfd, 0xcc, 0xaf, 0xa9, 0x84, 0x75, 0x5a, 0xc6, 0x28, 0x9f, 0xb3, 0xed, 0x66, 0x6a, 0xd4, 0x4f, 0xa8, 0x70, 0x1e, 0x44, 0xea, 0x70, 0xa3, 0xaa, 0xa4, 0xf5, 0xbd, 0x45, 0x9c, 0x10, 0x47, 0xdd, 0x8, 0x3c, 0x9e, 0x1f, 0xf5, 0xf3, 0xf3, 0x54, 0xba, 0xeb, 0xf3, 0x38, 0x8b, 0x4c, 0x4b, 0x37, 0xee, 0xbf, 0x17, 0xa0, 0xa2, 0x46, 0xb9, 0x87, 0xc4, 0x97, 0x5a, 0x6f, 0x80, 0x8a, 0x69, 0x3a, 0x3b, 0x66, 0x36, 0xc4, 0xff, 0x29, 0xac, 0xd, 0x3d, 0x35, 0x7d, 0xd7, 0x77, 0x78, 0x6f, 0xe2, 0x1, 0x63, 0xe4, 0x75, 0x75, 0xdc, 0x88, 0x65, 0x15, 0xa9, 0xd9, 0x90, 0x1, 0x95, 0x9, 0x34, 0x5d, 0x67, 0xd4, 0x7e, 0x4e, 0x6e, 0x46, 0xe5, 0x5c, 0xe3, 0x45, 0x43, 0xae, 0xc6, 0xfc, 0xf0, 0x99, 0xc0, 0xa7, 0x52, 0xf7, 0x3, 0xeb, 0xb7, 0x5b, 0x48, 0x6c, 0x25, 0xf8, 0x27, 0xbc, 0x6b, 0xfe, 0x97, 0x69, 0x4e, 0xef, 0x5c, 0x15, 0xb4, 0xe8, 0xc8, 0xfe, 0xde, 0xa3, 0x1, 0x1e, 0xc9, 0x9a, 0x46, 0x7a, 0xf7, 0xc6, 0x40, 0xd9, 0xca, 0xd1, 0x94, 0xba, 0xb2, 0x64, 0x23, 0x56, 0xfb, 0xb6, 0x98, 0xdb, 0x1d, 0xf7, 0x3d, 0xe2, 0x5a, 0x2, 0x3b, 0xb6, 0x98, 0x28, 0x3f, 0x49, 0x5b, 0x7, 0xbe, 0x27, 0xd9, 0x16, 0xc9, 0xe0, 0xf9, 0xa6, 0x46, 0x5f, 0x2d, 0x99, 0x7d, 0x8d, 0xb1, 0x25, 0xb2, 0x67, 0x7, 0xca, 0x9, 0x2a, 0x55, 0x3d, 0xa, 0xc9, 0xb8, 0xca, 0xd8, 0x3f, 0x92, 0xc3, 0x8a, 0x2e, 0xf5, 0x82, 0x65, 0x70, 0xbf, 0xd5, 0xdd, 0x4, 0xb5, 0xf4, 0x10, 0x3e, 0x29, 0xc4, 0x86, 0xa8, 0xb3, 0x6c, 0x98, 0xc8, 0xb6, 0x1e, 0x8d, 0x89, 0x2b, 0x9b, 0xf9, 0xb2, 0x28, 0xe1, 0x1e, 0x3e, 0xac, 0xcb, 0xc8, 0x97, 0xeb, 0xf4, 0xfd, 0x60, 0x26, 0x49, 0x3c, 0x1e, 0x97, 0xd1, 0x28, 0x52, 0xfb, 0xea, 0x17, 0x2f, 0x5b, 0xf5, 0x1, 0x69, 0x48, 0xcb, 0x3a, 0xdd, 0x9d, 0xe1, 0x3e, 0x4, 0x3e, 0xf1, 0x4, 0xcf, 0xe3, 0x94, 0x37, 0x52, 0x8d, 0x1a, 0x33, 0x82, 0x18, 0x53, 0x1e, 0xf8, 0x55, 0xb3, 0x4, 0xa7, 0x18, 0x55, 0x13, 0x11, 0x88, 0x7e, 0x2b, 0xa7, 0xbe, 0xb5, 0x5b, 0x8a, 0xe7, 0x36, 0x6d, 0x35, 0x93, 0x98, 0x16, 0xac, 0xa2, 0xed, 0x31, 0x57, 0x4c, 0xd9, 0xa6, 0x79, 0x8, 0x44, 0x72, 0xc2, 0x37, 0xd0, 0x67, 0xd9, 0x7a, 0xa4, 0x12, 0xd6, 0xce, 0xca, 0xe2, 0xb8, 0xb2, 0x22, 0x4d, 0xf0, 0x3a, 0xb0, 0x40, 0x43, 0x23, 0x7f, 0x2, 0x9c, 0xb6, 0xbb, 0xcc, 0x64, 0x9c, 0xe1, 0xb2, 0x6a, 0xd5, 0x84, 0x8b, 0xa5, 0x91, 0x51, 0xc9, 0xc0, 0x72, 0xa0, 0xc5, 0x13, 0x66, 0xfc, 0x73, 0x8, 0x41, 0x43, 0x4a, 0x4a, 0x9c, 0xc3, 0x3f, 0xc8, 0x75, 0x62, 0xe3, 0xbc, 0x8b, 0x5c, 0x34, 0x23, 0xc, 0x9d, 0x25, 0xc9, 0x27, 0xf1, 0x34, 0x76, 0xb3, 0x75, 0xca, 0xfb, 0x74, 0xf1, 0x79, 0x21, 0x40, 0xaa, 0xf2, 0x30, 0x63, 0xb, 0x69, 0xa2, 0xaa, 0xf5, 0x7b, 0x3a, 0xd4, 0x5f, 0x40, 0x7b, 0xfc, 0xd4, 0x93, 0x6c, 0x5a, 0x47, 0x51, 0xa, 0x1, 0xa, 0xc4, 0xa2, 0x3d, 0x54, 0xdd, 0x63, 0x6a, 0xb, 0xb7, 0x0, 0x6a, 0x25, 0x45, 0x29, 0x4, 0x86, 0xf2, 0x29, 0x92, 0x7c, 0x66, 0x69, 0xc7, 0xa2, 0x73, 0x85, 0x48, 0xb2, 0x5f, 0x2f, 0x23, 0x1d, 0xf1, 0xf8, 0x76, 0x1b, 0xe5, 0xd3, 0x46, 0x35, 0xf2, 0xbb, 0x8b, 0x7e, 0x4e, 0x72, 0x61, 0xc, 0xb0, 0x33, 0x6, 0x2f, 0x52, 0x4e, 0x61, 0xa6, 0x84, 0x20, 0x54, 0x5a, 0xb8, 0xe4, 0x60, 0x16, 0x99, 0x7b, 0x72, 0x62, 0xec, 0x94, 0x81, 0xe, 0x8d, 0xf4, 0x72, 0x9f, 0x60, 0xb2, 0xae, 0x90, 0x48, 0x4d, 0x69, 0xad, 0xe3, 0x9e, 0xe9, 0x9e, 0xe9, 0xf7, 0x40, 0x9d, 0x75, 0x77, 0xc7, 0x4c, 0xbd, 0x62, 0xcf, 0xa2, 0x3b, 0xb7, 0x54, 0xc4, 0x55, 0x3c, 0xd4, 0xf9, 0x54, 0x73, 0xa8, 0xd, 0xda, 0x4e, 0x65, 0xd1, 0xfa, 0x2, 0xbe, 0x69, 0x8a, 0x3e, 0xc3, 0x77, 0x33, 0xf4, 0x5b, 0x46, 0xc, 0x4e, 0xc0, 0xa5, 0xe2, 0xd5, 0x4, 0x4b, 0xab, 0x1, 0xfa, 0x3d, 0x5c, 0x8, 0x94, 0x61, 0xa, 0xb1, 0xa8, 0xe4, 0x53, 0xd2, 0x62, 0x7, 0x8a, 0xc4, 0x0, 0x8b, 0x2b, 0xd1, 0xf7, 0x0, 0x55, 0xac, 0x25, 0x8, 0xdc, 0x86, 0xca, 0x7, 0x3a, 0x40, 0xa7, 0x17, 0x79, 0x65, 0x67, 0x79, 0x71, 0x60, 0xe9, 0x70, 0xdb, 0x3d, 0x3b, 0x9a, 0xb9, 0x76, 0x26, 0xce, 0x3a, 0x39, 0xc6, 0x1d, 0x8b, 0xf, 0xf2, 0x72, 0xe9, 0x21, 0xe4, 0xd, 0x7, 0x6f, 0x2f, 0xeb, 0x8, 0xf8, 0xd3, 0x2, 0x31, 0x16, 0xb7, 0xb6, 0x79, 0xe3, 0x80, 0x9, 0x46, 0x10, 0xa7, 0xba, 0x5c, 0xbd, 0x45, 0x22, 0x9c, 0xc1, 0xde, 0xaf, 0xa3, 0x77, 0x4f, 0xe6, 0x14, 0x1b, 0x87, 0x70, 0x3d, 0x47, 0x63, 0x24, 0xcb, 0x6f, 0xcc, 0x18, 0x9, 0x95, 0x9c, 0x3f, 0xba, 0x91, 0xed, 0xa8, 0x2e, 0x79, 0x35, 0xb7, 0x5f, 0xb3, 0x47, 0x2f, 0xa5, 0xac, 0x52, 0xc3, 0x42, 0x62, 0xe9, 0xf3, 0xac, 0xad, 0x26, 0x24, 0x13, 0x86, 0x54, 0xc5, 0x20, 0x4e, 0xc, 0xb4, 0x94, 0x33, 0xcb, 0x6f, 0xed, 0x84, 0x6b, 0xb4, 0x71, 0x9d, 0x65, 0x2d, 0x74, 0xf2, 0xeb, 0x68, 0xdc, 0x4a, 0xf, 0xa0, 0xae, 0x74, 0x3, 0xc6, 0x15, 0x6b, 0x2a, 0x82, 0x9d, 0x66, 0x2c, 0x82, 0xa7, 0x88, 0xe5, 0xa4, 0x5a, 0xc0, 0x7, 0x6, 0x93, 0xe8, 0x2c, 0x6c, 0x54, 0xc7, 0x8e, 0xec, 0x44, 0x1, 0x93, 0x96, 0x84, 0x49, 0xd1, 0xc4, 0x71, 0x24, 0x85, 0xaa, 0x7, 0x67, 0xb0, 0xda, 0xc, 0xf3, 0xcd, 0xe5, 0x84, 0xaa, 0x40, 0x45, 0x7f, 0xf7, 0xc9, 0x1c, 0xae, 0x89, 0x22, 0xc6, 0x34, 0xd3, 0x7a, 0x68, 0x2e, 0xdd, 0x54, 0x83, 0xd5, 0xa9, 0xaf, 0xb2, 0x7f, 0xea, 0x2d, 0x63, 0x55, 0x88, 0x4a, 0x79, 0x50, 0xf4, 0x93, 0x54, 0x2b, 0x3e, 0x44, 0xf3, 0x78, 0x13, 0xf7, 0xf6, 0x83, 0x6f, 0x38, 0x4, 0x39, 0x81, 0xc5, 0x6c, 0xb2, 0x8d, 0xd7, 0xc9, 0x99, 0x35, 0x3d, 0x7c, 0x84, 0x87, 0x2d, 0x25, 0x2a, 0xd, 0x9b, 0x21, 0xc0, 0x18, 0xad, 0x29, 0xf2, 0x98, 0x61, 0x5c, 0x3d, 0xb5, 0xcd, 0x10, 0x71, 0x90, 0x2d, 0x99, 0x19, 0x5e, 0xcd, 0x7c, 0x9, 0xdb, 0xd8, 0x8d, 0xb2, 0xa9, 0x23, 0xb4, 0x5c, 0x88, 0x41, 0xd1, 0xcc, 0xc, 0xaa, 0xa1, 0x15, 0xe9, 0x12, 0x6b, 0xd0, 0x12, 0xaa, 0xf, 0x95, 0x2f, 0xf0, 0x49, 0xe1, 0x84, 0x7e, 0xb1, 0x65, 0x10, 0x32, 0xc5, 0xd3, 0xca, 0x22, 0x14, 0x55, 0x22, 0x0, 0x78, 0xe0, 0xb, 0xea, 0xa2, 0x31, 0x11, 0x48, 0x22, 0xa8, 0x96, 0x43, 0x74, 0xd2, 0xbc, 0xba, 0x32, 0xd, 0xc9, 0x86, 0x9d, 0xe1, 0xa3, 0x49, 0xe9, 0x82, 0x11, 0x2a, 0xdb, 0x30, 0x30, 0x5a, 0x8f, 0x75, 0x5d, 0x7b, 0xc0, 0x26, 0x81, 0x9c, 0xee, 0x99, 0xf0, 0xa8, 0x2f, 0x24, 0x56, 0x9c, 0x43, 0x1b, 0xe1, 0x8d, 0xb3, 0x53, 0x8b, 0x92, 0x2d, 0xa3, 0x55, 0x62, 0xdd, 0xea, 0x2f, 0x8a, 0x18, 0xc3, 0xb8, 0x84, 0xc8, 0x8c, 0x98, 0x22, 0x9, 0x99, 0xd6, 0xce, 0xc3, 0xe9, 0x33, 0x68, 0xb5, 0xf5, 0x19, 0xd4, 0x76, 0xb0, 0xc7, 0xf7, 0x69, 0x5c, 0x68, 0x1b, 0x21, 0x2f, 0x6c, 0x10, 0x4, 0x98, 0x29, 0xee, 0x30, 0xa9, 0x71, 0xf9, 0x0, 0x62, 0x3, 0x11, 0x52, 0xc2, 0xf0, 0x4b, 0x22, 0xa3, 0x6c, 0xb, 0x1f, 0xdc, 0x7d, 0xac, 0xa5, 0x5f, 0x15, 0x4b, 0xd, 0x1a, 0x9c, 0xca, 0x29, 0x5, 0x2d, 0x36, 0x12, 0x22, 0xc6, 0x4, 0x41, 0xad, 0xd6, 0x8a, 0x8b, 0x6e, 0x13, 0x12, 0x43, 0xfc, 0x4d, 0xec, 0x56, 0xc9, 0x32, 0x89, 0x59, 0x4a, 0xc4, 0xf9, 0xa9, 0x22, 0xe7, 0x6c, 0x4a, 0xf0, 0xaa, 0xb5, 0x29, 0x6b, 0xc5, 0xf, 0x45, 0x81, 0xec, 0x2e, 0xe2, 0x7e, 0xb2, 0x55, 0x2c, 0x2f, 0x54, 0x2e, 0x65, 0xe9, 0x5a, 0x2b, 0xe, 0x21, 0xde, 0x8, 0x13, 0xc6, 0x27, 0x60, 0x41, 0x68, 0x89, 0x3e, 0x1f, 0xf2, 0xd8, 0x51, 0x14, 0x9, 0x6e, 0x15, 0xc, 0xf9, 0xdd, 0xb0, 0xe9, 0xc8, 0x2a, 0x59, 0x65, 0x62, 0x81, 0xc6, 0x9d, 0x29, 0x79, 0x8e, 0x24, 0x45, 0xae, 0x4a, 0xf5, 0xee, 0xa6, 0x47, 0xf6, 0xd2, 0x5b, 0x36, 0xb7, 0xfe, 0x90, 0xf5, 0xb5, 0x86, 0x3d, 0xfb, 0xe8, 0xb1, 0xc8, 0x5f, 0x40, 0x53, 0x93, 0xcf, 0x17, 0xbf, 0xcc, 0xdd, 0x28, 0xaa, 0x29, 0x1c, 0xaf, 0x7d, 0x4, 0xb9, 0xf1, 0xd0, 0x2d, 0x58, 0xef, 0xed, 0x35, 0x92, 0x76, 0xf3, 0xd1, 0xfa, 0x6e, 0x6, 0x37, 0x77, 0x89, 0x46, 0x0, 0xfa, 0x3, 0xf1, 0x47, 0x9d, 0x86, 0x70, 0x46, 0x20, 0x3c, 0x43, 0x70, 0x4c, 0x95, 0xa2, 0xb4, 0x9b, 0xb3, 0x6b, 0x76, 0x20, 0x1c, 0x89, 0x60, 0x15, 0xeb, 0x27, 0x77, 0xb3, 0x1a, 0x8c, 0x12, 0x2a, 0x4c, 0xbb, 0x12, 0xd6, 0xd2, 0x46, 0x7b, 0x1c, 0x24, 0x2f, 0x42, 0xbd, 0x6, 0xcf, 0xcc, 0xd8, 0xa, 0x88, 0x65, 0xe4, 0xb2, 0x27, 0xd3, 0xb0, 0xf9, 0xb1, 0xd6, 0x3d, 0x12, 0x8e, 0x2a, 0x5f, 0xb5, 0x1b, 0x8d, 0xef, 0x47, 0xcc, 0x13, 0xbc, 0xfd, 0xb3, 0xa1, 0x32, 0xf5, 0xb4, 0xb9, 0xc9, 0x99, 0x48, 0x80, 0x7b, 0xb3, 0x10, 0x16, 0x32, 0x6d, 0x1c, 0xa7, 0x73, 0x70, 0x98, 0x74, 0x75, 0x35, 0x47, 0x30, 0xd7, 0x27, 0x13, 0xe0, 0x60, 0xeb, 0x20, 0x87, 0x8b, 0xfa, 0x80, 0x71, 0x69, 0x68, 0x3e, 0xe1, 0x56, 0x9f, 0x82, 0xa0, 0x1d, 0x97, 0x26, 0x54, 0xb, 0x8b, 0x70, 0xf, 0x8f, 0x66, 0x73, 0x95, 0xb, 0x5, 0xd9, 0x2f, 0x97, 0xd2, 0x52, 0xc8, 0xe6, 0xcf, 0x25, 0x6, 0x9f, 0x81, 0x17, 0x45, 0xf0, 0x8e, 0x41, 0x19, 0xfb, 0x99, 0x81, 0xd7, 0x90, 0x25, 0xad, 0xc9, 0x4, 0x52, 0xcf, 0xa7, 0x6b, 0x27, 0xbe, 0xe2, 0xe1, 0x59, 0x72, 0x89, 0x9f, 0x51, 0x3f, 0xf6, 0xa4, 0x1f, 0xbf, 0x5, 0xd2, 0x2d, 0x25, 0xca, 0x62, 0x12, 0x8e, 0x75, 0x3, 0x20, 0x59, 0x29, 0xdd, 0x14, 0xd9, 0x5c, 0x9, 0xd7, 0x22, 0x35, 0xf2, 0xc0, 0x57, 0xb9, 0xb1, 0xea, 0x8f, 0xb1, 0xb1, 0xfa, 0x33, 0x70, 0xe7, 0x94, 0xb1, 0xbf, 0xcb, 0x7b, 0x92, 0x8e, 0x81, 0x2d, 0x34, 0xe2, 0x2b, 0xdb, 0x12, 0x5e, 0x84, 0x22, 0xbf, 0x75, 0xba, 0xbd, 0x27, 0xf5, 0xdb, 0x36, 0xa0, 0x72, 0x12, 0x3c, 0xf1, 0xac, 0x88, 0x4a, 0xca, 0x43, 0xab, 0x74, 0x8d, 0x15, 0xb5, 0x44, 0x94, 0x4b, 0x4d, 0x61, 0x9a, 0x8d, 0xe9, 0xca, 0xd6, 0xa4, 0xff, 0x1e, 0x80, 0xb9, 0x3, 0xf3, 0xb8, 0x53, 0x17, 0x40, 0xe2, 0x2d, 0x34, 0xc0, 0x69, 0xa3, 0x74, 0xd1, 0x27, 0xde, 0x3e, 0x95, 0x4c, 0xf0, 0x73, 0x81, 0x14, 0x95, 0x1d, 0xb1, 0x36, 0x5c, 0x5d, 0xff, 0x3a, 0xf9, 0x87, 0x32, 0x8e, 0x38, 0xa9, 0xe4, 0xea, 0xd4, 0x54, 0x92, 0xb4, 0xbe, 0x9d, 0x1, 0x22, 0xc6, 0x31, 0xe0, 0x27, 0x26, 0xd8, 0x41, 0x55, 0xba, 0x4a, 0x6, 0xc3, 0x27, 0x3, 0x9a, 0xb9, 0x6a, 0x36, 0x1b, 0x23, 0x42, 0x7e, 0x5d, 0x8e, 0x70, 0xca, 0x77, 0x95, 0x9c, 0x7c, 0xbc, 0x87, 0x63, 0x3, 0x46, 0x24, 0xf, 0xf6, 0x92, 0xa2, 0xc2, 0x9a, 0xc2, 0x1c, 0x8a, 0x6c, 0xf4, 0x0, 0x32, 0xc2, 0xdb, 0x10, 0xc9, 0xa3, 0xbe, 0x7c, 0xb1, 0x3d, 0x48, 0xe7, 0x3d, 0xaa, 0x5a, 0x8d, 0xb7, 0xac, 0x96, 0xbf, 0x4c, 0x65, 0xa3, 0x91, 0xb8, 0xca, 0x25, 0xce, 0xa1, 0xb1, 0xb3, 0xf3, 0x9b, 0xb1, 0xd2, 0xe2, 0xa3, 0x9c, 0xed, 0xe8, 0x3a, 0x8d, 0xb9, 0xd3, 0xa7, 0xd5, 0x9, 0xfc, 0xd5, 0x8c, 0xe5, 0xea, 0x65, 0xa, 0xfa, 0xf6, 0xe4, 0x95, 0x74, 0x42, 0xfd, 0x21, 0x81, 0x86, 0xbf, 0x0, 0x54, 0xa4, 0x7, 0xd6, 0xd3, 0x5f, 0x23, 0xa4, 0xb2, 0xf0, 0xb0, 0x18, 0x9e, 0x8e, 0x17, 0x4c, 0x6d, 0x9a, 0x58, 0xe4, 0x9b, 0xce, 0x5d, 0x3b, 0xad, 0x3, 0x92, 0x8a, 0x3f, 0xa8, 0xa8, 0xe4, 0xec, 0x42, 0xd6, 0x13, 0x2e, 0xe7, 0x61, 0x20, 0x8d, 0x68, 0x55, 0x35, 0x6b, 0x7f, 0x50, 0x5c, 0xe0, 0x70, 0x21, 0x6a, 0x9b, 0x50, 0xd, 0xdb, 0xd8, 0xd9, 0xc3, 0x32, 0x7d, 0xb9, 0x2c, 0xbb, 0xe0, 0xb7, 0x57, 0xd9, 0xaf, 0x9b, 0x15, 0x68, 0x2e, 0xba, 0x78, 0x7a, 0x57, 0x8a, 0xd4, 0xf2, 0xf4, 0xc2, 0xe9, 0x56, 0x9f, 0x64, 0x8b, 0x34, 0x2, 0xc6, 0x8c, 0x23, 0x84, 0x7c, 0x54, 0x29, 0x7e, 0x43, 0x25, 0x4, 0xc3, 0xca, 0x90, 0xbb, 0xcf, 0x34, 0x73, 0x92, 0xeb, 0xa0, 0xa9, 0x32, 0xda, 0xa1, 0x7, 0x72, 0xd2, 0x6f, 0x77, 0x84, 0x7e, 0xf9, 0x14, 0x25, 0xea, 0x88, 0x7a, 0x7c, 0x72, 0x8a, 0x1f, 0x91, 0x18, 0xc1, 0xa0, 0x27, 0xef, 0x28, 0xf5, 0xc7, 0x68, 0x0, 0x96, 0x5b, 0x8c, 0xba, 0x7c, 0xf8, 0x56, 0x91, 0x7b, 0x9c, 0x4b, 0x18, 0x32, 0xf2, 0x36, 0x65, 0x78, 0xb3, 0x8f, 0x48, 0xf0, 0xde, 0x8a, 0x6e, 0x16, 0x66, 0xa1, 0xe3, 0x53, 0xf9, 0xd, 0x5e, 0x66, 0xad, 0xe8, 0xbb, 0xe8, 0x2b, 0x87, 0x9d, 0xf, 0x45, 0x4a, 0x9, 0x36, 0xa7, 0x5f, 0xa, 0x98, 0xa8, 0xc6, 0x3f, 0x56, 0x21, 0x4, 0xe1, 0x47, 0xdf, 0x6, 0xd1, 0x5d, 0xdd, 0xca, 0x99, 0x5a, 0xfa, 0x65, 0x82, 0xa2, 0xf7, 0xd9, 0xa7, 0xf0, 0xb1, 0x24, 0xe1, 0x6, 0xc7, 0x1, 0xa9, 0x22, 0x52, 0xc5, 0xfe, 0x98, 0x22, 0x4e, 0xd5, 0xf0, 0x63, 0x68, 0x53, 0x1, 0xf5, 0xad, 0x7d, 0x98, 0x4f, 0x6c, 0x11, 0x6, 0xf3, 0x84, 0xb8, 0x8a, 0xbc, 0xcc, 0x8a, 0x7e, 0x6, 0x93, 0x6b, 0x94, 0x75, 0x2d, 0xba, 0x7f, 0x1, 0xbc, 0x15, 0xf2, 0xb, 0x82, 0x36, 0x28, 0x67, 0x4d, 0xc, 0xb0, 0xb9, 0x40, 0xd4, 0x92, 0x44, 0xe8, 0xbd, 0x55, 0xc2, 0xbb, 0xed, 0x72, 0x7e, 0xb1, 0x50, 0xfd, 0xd4, 0xdc, 0xf5, 0xda, 0xd6, 0xe, 0x43, 0xdc, 0x58, 0x5, 0x66, 0xde, 0x7a, 0x78, 0xc8, 0x2b, 0xaf, 0x58, 0x31, 0xef, 0xbd, 0xb6, 0xa4, 0x6e, 0x76, 0xb3, 0x6a, 0x35, 0x8e, 0xe9, 0x1b, 0x8b, 0xd0, 0x5a, 0x31, 0x57, 0xf9, 0xa4, 0x14, 0x9e, 0x51, 0x8b, 0x92, 0x3, 0x71, 0xc4, 0x8a, 0x5f, 0x1a, 0xee, 0x4, 0x4b, 0x6c, 0x71, 0x38, 0x33, 0x1e, 0x46, 0x2c, 0x56, 0xaf, 0x9c, 0x60, 0x2, 0xc5, 0x88, 0xc, 0x79, 0x3, 0xe, 0xf, 0xb3, 0x38, 0x6a, 0x19, 0x28, 0xcf, 0x35, 0xa9, 0xe2, 0x5b, 0x92, 0x2d, 0x5e, 0x92, 0xed, 0x5c, 0x88, 0xbd, 0xcc, 0xf0, 0x6f, 0x2e, 0xf4, 0x7d, 0x8, 0xbf, 0xa3, 0x8a, 0x7e, 0xa7, 0xc3, 0x97, 0x1b, 0x18, 0x4f, 0x39, 0xeb, 0x47, 0x6, 0x6, 0xd8, 0x29, 0x11, 0x2, 0x2c, 0x0, 0xd4, 0x85, 0x99, 0xcf, 0xc3, 0x4b, 0x9f, 0x4d, 0xad, 0x42, 0x94, 0x35, 0xc4, 0xba, 0x43, 0x7f, 0x46, 0xc, 0x7f, 0x6b, 0xaf, 0x15, 0x2e, 0xbf, 0x87, 0x6, 0x5d, 0xeb, 0x2d, 0xcb, 0xbf, 0x99, 0x5f, 0xe0, 0x5, 0xdc, 0xef, 0x8b, 0x2f, 0x46, 0x8c, 0x3c, 0xc1, 0x62, 0x93, 0x1c, 0x89, 0xbe, 0x68, 0xfa, 0xb4, 0x86, 0xce, 0x1b, 0xb1, 0xdc, 0x47, 0x3e, 0x73, 0x2c, 0xf4, 0x94, 0xd9, 0x1a, 0xeb, 0xf9, 0x73, 0xb4, 0xb1, 0x59, 0xff, 0x88, 0x16, 0x54, 0x46, 0x7, 0x31, 0xeb, 0xc, 0x64, 0xd9, 0x92, 0xc, 0xb6, 0x3e, 0xe9, 0x80, 0x8f, 0x89, 0xbc, 0x13, 0x93, 0x7, 0x25, 0x5b, 0xc4, 0xaf, 0xe1, 0xcf, 0xa0, 0x8e, 0x31, 0x64, 0xa4, 0xcd, 0x73, 0x46, 0x1a, 0x5, 0x15, 0x23, 0x94, 0x55, 0x6b, 0x56, 0x31, 0x45, 0x4a, 0xe9, 0x5e, 0xea, 0xdc, 0x70, 0x5c, 0x27, 0x5e, 0x3, 0xc, 0x64, 0xe8, 0x1d, 0x84, 0x95, 0xb5, 0x3b, 0x65, 0xe5, 0x63, 0x75, 0x5a, 0x15, 0x3f, 0xe5, 0xfa, 0x84, 0x30, 0x89, 0x40, 0xba, 0x94, 0x5c, 0xcc, 0x84, 0x4f, 0x6, 0x40, 0xf8, 0x42, 0x4c, 0xf1, 0xa6, 0x3e, 0xd, 0x2c, 0xb8, 0xa3, 0xa, 0xc7, 0xce, 0x3d, 0x4f, 0xba, 0xdf, 0xfd, 0x5f, 0x58, 0xd2, 0x87, 0x1a, 0x8a, 0xab, 0x17, 0x56, 0xf6, 0x1d, 0x85, 0xd7, 0x6f, 0x15, 0xb9, 0xad, 0xf4, 0x16, 0x70, 0x7a, 0xc8, 0xe6, 0x45, 0xc3, 0x99, 0xb1, 0x26, 0x92, 0xec, 0x3, 0xc, 0xf6, 0xf7, 0xef, 0x90, 0x8e, 0x16, 0x49, 0x2d, 0xe2, 0xba, 0x91, 0xd9, 0xbc, 0x68, 0xdc, 0x7f, 0xf1, 0x4, 0xc7, 0xda, 0x85, 0x40, 0x59, 0xec, 0x3e, 0x85, 0x99, 0x98, 0x63, 0xac, 0x86, 0x24, 0xa9, 0xe9, 0x7, 0x8c, 0x35, 0x73, 0x94, 0x14, 0xda, 0xa1, 0x11, 0xc, 0xff, 0xa8, 0xd4, 0x55, 0xf9, 0x9c, 0x9b, 0xec, 0x92, 0xd4, 0x9e, 0x6a, 0x6a, 0x14, 0xf5, 0x7f, 0x5, 0x6b, 0xc, 0x94, 0xf3, 0xc7, 0x52, 0xfb, 0x3b, 0x8b, 0xe9, 0xa, 0xdb, 0xcf, 0x54, 0xa3, 0x6d, 0x45, 0x4e, 0xa, 0x63, 0x42, 0xb4, 0xd3, 0x50, 0x1b, 0x8a, 0xcb, 0x45, 0x94, 0x11, 0x33, 0x50, 0xb1, 0xe1, 0xb9, 0x5, 0x91, 0xd0, 0x80, 0x3b, 0xa3, 0x9c, 0x8c, 0x21, 0x66, 0xa, 0xb4, 0x20, 0xc4, 0x44, 0x4, 0xa, 0xd4, 0x59, 0xea, 0xe0, 0x0, 0x60, 0x60, 0x80, 0x2f, 0xf4, 0x43, 0xb, 0xc6, 0x2e, 0x30, 0xaa, 0x1a, 0xb8, 0x92, 0x2d, 0xd0, 0xf7, 0x18, 0xd7, 0xe, 0x7d, 0xc1, 0x42, 0x6b, 0x42, 0x7, 0x5, 0xca, 0x7c, 0x11, 0x52, 0xc7, 0xbb, 0xee, 0x51, 0x9e, 0xa, 0x1a, 0xa3, 0x46, 0x29, 0xb3, 0xc1, 0x37, 0x3b, 0x34, 0x78, 0xb9, 0x52, 0x0, 0x3c, 0xf0, 0xc4, 0x16, 0xc2, 0xec, 0x2b, 0xea, 0x44, 0x89, 0xd2, 0xf5, 0x53, 0xca, 0x18, 0x3f, 0x10, 0xa1, 0x3a, 0x8, 0x5a, 0x5, 0x23, 0xd8, 0x44, 0x65, 0xb7, 0x4, 0xe0, 0x59, 0x42, 0x6a, 0x52, 0x54, 0x66, 0xd4, 0x7d, 0xa0, 0x43, 0x4, 0xe5, 0x3f, 0x32, 0xe1, 0xdd, 0xc3, 0x74, 0xa5, 0x12, 0x21, 0x2a, 0x9a, 0x22, 0xad, 0xc3, 0x43, 0x40, 0x56, 0x76, 0x81, 0x74, 0x4a, 0x64, 0x33, 0x9e, 0x7b, 0x83, 0x59, 0xb3, 0x91, 0xcc, 0x55, 0x6a, 0x6f, 0x69, 0x91, 0x4a, 0x80, 0xb4, 0xa0, 0xeb, 0xd0, 0xcc, 0xbc, 0xab, 0xfc, 0xcc, 0xbc, 0x6, 0x4c, 0x45, 0xbe, 0xf7, 0xd, 0xaa, 0x98, 0x88, 0xe6, 0x10, 0x18, 0x9, 0x12, 0xf9, 0x5, 0x83, 0xc2, 0xa8, 0x5d, 0x55, 0x78, 0x98, 0x8a, 0xbf, 0x3, 0x86, 0x4, 0xc3, 0xb5, 0x40, 0x6b, 0x84, 0xb4, 0x11, 0xd2, 0xe8, 0x40, 0x37, 0x80, 0xe4, 0x86, 0xab, 0x5f, 0xe, 0xe2, 0xc4, 0xed, 0x9e, 0xe6, 0x6a, 0x29, 0xf5, 0x12, 0x3, 0x4d, 0x62, 0xb9, 0xd3, 0x55, 0x51, 0xd8, 0xe4, 0x58, 0x9e, 0xf1, 0x41, 0x8b, 0x7a, 0xf2, 0xc0, 0x28, 0xae, 0x4, 0xd3, 0xe5, 0x68, 0x7a, 0x80, 0x6f, 0xba, 0x50, 0xbd, 0xdc, 0xdd, 0x23, 0xf1, 0x61, 0xb4, 0x9, 0xa7, 0x46, 0x54, 0x2, 0x8d, 0x69, 0x44, 0xa5, 0xad, 0x70, 0xf7, 0xa9, 0xbf, 0x11, 0xe, 0x25, 0x39, 0x72, 0xfe, 0x26, 0xc4, 0x5e, 0xbe, 0xd3, 0x8a, 0x19, 0xfe, 0x9, 0x6e, 0xbc, 0x1f, 0xc8, 0x68, 0xee, 0x17, 0x17, 0xa4, 0x3e, 0xec, 0xc3, 0x51, 0x29, 0xca, 0xaf, 0x88, 0x7a, 0x2e, 0xfc, 0x45, 0x4c, 0x2f, 0xb4, 0xee, 0x1f, 0xa4, 0x2a, 0xac, 0x7d, 0xa0, 0x1c, 0x52, 0x6c, 0x4e, 0x21, 0x7b, 0x48, 0x58, 0xca, 0xa7, 0x1d, 0x6e, 0x82, 0x96, 0x8, 0x8, 0x2, 0x1b, 0x3e, 0xa2, 0x3a, 0x20, 0x79, 0x4, 0xa4, 0xe0, 0x45, 0xe4, 0x2c, 0xc8, 0x84, 0x69, 0xe8, 0x9b, 0x76, 0x1, 0xde, 0x4c, 0x6, 0x4a, 0x8b, 0x84, 0xb8, 0x2d, 0xc2, 0x18, 0x31, 0x6, 0x18, 0x22, 0xd5, 0x6c, 0x27, 0x15, 0x81, 0x76, 0x86, 0x2b, 0x8d, 0x22, 0xd4, 0x3c, 0x9f, 0x4c, 0xaa, 0xb3, 0x27, 0xa, 0x94, 0x5d, 0xe4, 0x74, 0xe, 0x2b, 0xd4, 0x12, 0xf, 0x3c, 0x8b, 0x87, 0xd, 0xe, 0x26, 0xe, 0x0, 0x7e, 0xe4, 0x4b, 0xb1, 0x52, 0x9d, 0xc1, 0xea, 0x21, 0xc9, 0x8c, 0x59, 0x9d, 0xbd, 0xc1, 0x81, 0xae, 0x2e, 0x78, 0x98, 0x72, 0x28, 0x56, 0xb9, 0x99, 0x43, 0xd5, 0x55, 0x29, 0xbe, 0x52, 0x17, 0x8d, 0xf2, 0x4d, 0x2e, 0xf0, 0x27, 0x5, 0x17, 0xe5, 0x70, 0x80, 0xa, 0xb4, 0x18, 0x1e, 0x23, 0x96, 0x26, 0xca, 0xaa, 0xfc, 0x3e, 0x96, 0xe8, 0xe9, 0xaf, 0x33, 0xe9, 0x90, 0xee, 0x6c, 0x8f, 0x55, 0xa, 0xbe, 0xc7, 0xf2, 0x1d, 0x21, 0x7e, 0xd8, 0x81, 0xdf, 0xec, 0x12, 0x34, 0xc5, 0xf3, 0x1b, 0xa5, 0x2f, 0x88, 0x6, 0x85, 0x83, 0xa, 0x9b, 0xc, 0xf8, 0xb0, 0x97, 0xb0, 0x25, 0x97, 0x5, 0x48, 0xd5, 0xc4, 0x5a, 0x10, 0x2c, 0xb8, 0xc1, 0xa6, 0x70, 0x44, 0x2d, 0x51, 0x70, 0xd0, 0x80, 0xc, 0xa8, 0x4b, 0x5a, 0xc7, 0xd4, 0x4, 0xc8, 0xae, 0x32, 0xb1, 0x8f, 0x31, 0xca, 0x2e, 0xdd, 0x1f, 0x13, 0x85, 0x2b, 0xaa, 0xe0, 0x96, 0xc4, 0xe2, 0xa5, 0xae, 0x14, 0x13, 0x25, 0x2d, 0x51, 0x6d, 0x5a, 0xb5, 0x95, 0x3e, 0xf5, 0xf2, 0xea, 0xd8, 0x44, 0x5c, 0x6e, 0x19, 0x89, 0xe, 0xa8, 0xa4, 0xbb, 0xe1, 0xb6, 0x37, 0x5f, 0x90, 0x76, 0x84, 0xd8, 0x9c, 0x31, 0xea, 0x51, 0x71, 0x76, 0xc, 0x1d, 0xfe, 0x12, 0xcd, 0xe2, 0x0, 0xd6, 0xc8, 0x65, 0x3, 0x28, 0x15, 0xb, 0x67, 0x24, 0x68, 0xbb, 0x2f, 0x4b, 0x83, 0x88, 0x78, 0x11, 0xe5, 0x8b, 0x8c, 0x20, 0xb9, 0x5c, 0x5b, 0x6e, 0xab, 0xd4, 0x4d, 0x56, 0x87, 0xca, 0x68, 0x39, 0x3d, 0x41, 0x2, 0x1c, 0x35, 0xf0, 0x8c, 0x75, 0x83, 0x49, 0xc4, 0x65, 0x6d, 0x91, 0xf5, 0x82, 0x2f, 0x2b, 0x7c, 0x41, 0xbb, 0xf9, 0xd3, 0x3, 0x94, 0x7e, 0x25, 0x41, 0x42, 0xd5, 0xc3, 0xf9, 0x3b, 0x97, 0x51, 0xc0, 0xa5, 0x5d, 0x4a, 0xb2, 0xae, 0x71, 0xce, 0xcb, 0x19, 0x4, 0xf3, 0x84, 0x5b, 0xd8, 0xdc, 0x39, 0xa0, 0xf4, 0x46, 0xa1, 0xc9, 0x21, 0xcd, 0x20, 0xdd, 0x20, 0xed, 0x9a, 0x9a, 0xd7, 0x4, 0x1b, 0xa4, 0x95, 0x68, 0x6, 0x52, 0xa8, 0xd1, 0x43, 0x4b, 0x83, 0xb4, 0xe0, 0x19, 0x1b, 0x1c, 0x9b, 0x11, 0x16, 0x14, 0xd6, 0xc9, 0x3a, 0x40, 0xd7, 0x49, 0x48, 0xf9, 0x8c, 0x3, 0x96, 0x3, 0x2a, 0xf4, 0xd1, 0x1e, 0x64, 0xd1, 0xa9, 0x65, 0x52, 0xce, 0xcc, 0x34, 0xda, 0x2a, 0x92, 0x31, 0x1b, 0x64, 0xe0, 0x8b, 0xee, 0x0, 0xe5, 0x21, 0x76, 0xa, 0x5, 0x5c, 0xa3, 0x71, 0x6b, 0x58, 0x7b, 0x89, 0x1b, 0x5d, 0xba, 0x4a, 0x2f, 0x57, 0xf5, 0x31, 0xf9, 0x70, 0x4f, 0x31, 0x69, 0xcd, 0x40, 0x18, 0xb9, 0x4, 0x6c, 0x76, 0x7f, 0x91, 0x6e, 0x22, 0x52, 0x5b, 0x8, 0x32, 0x12, 0x1f, 0x68, 0x2f, 0xcb, 0xaf, 0x1, 0x19, 0x81, 0x53, 0x9c, 0x9b, 0x1c, 0x5e, 0x4b, 0x9a, 0x5a, 0x79, 0x8e, 0x42, 0x9f, 0x10, 0x19, 0xa5, 0x5e, 0xd9, 0x4d, 0x7b, 0xf4, 0x96, 0xb6, 0x20, 0xb, 0xb1, 0x29, 0xe2, 0x58, 0xdf, 0xb0, 0x30, 0x8b, 0xa1, 0x3, 0xd5, 0x20, 0x40, 0xf1, 0x4f, 0xe4, 0xc3, 0xd, 0x9a, 0x11, 0x20, 0xd9, 0x6c, 0x41, 0xb, 0xd9, 0x16, 0xd8, 0xf, 0xcc, 0xa4, 0x79, 0xb8, 0x85, 0xfb, 0x9e, 0x46, 0x51, 0xaa, 0x15, 0x10, 0xab, 0xa2, 0x63, 0xde, 0xf4, 0xa0, 0x2a, 0xa0, 0x13, 0x46, 0xec, 0xb3, 0x58, 0xfd, 0x4e, 0x6a, 0xb6, 0x29, 0x5a, 0xa0, 0xa5, 0xda, 0x1f, 0x25, 0xa2, 0x2c, 0x10, 0x0, 0xe0, 0x5f, 0x94, 0x56, 0xa4, 0x1a, 0x9a, 0x5c, 0x18, 0x5c, 0xa6, 0x59, 0xb, 0x3a, 0x1d, 0xd9, 0x9d, 0x4c, 0x3d, 0x2c, 0x75, 0x5e, 0xc0, 0x15, 0xa, 0xc0, 0xe3, 0x84, 0x8, 0x39, 0xb, 0x82, 0x70, 0xe5, 0x21, 0xa4, 0xdd, 0x21, 0x40, 0xca, 0xb4, 0x9e, 0x4d, 0xe9, 0x6, 0xce, 0xd5, 0xe2, 0x2d, 0x8f, 0xe3, 0x5, 0x0, 0x30, 0xea, 0x16, 0xca, 0xa5, 0x37, 0x0, 0x7f, 0xe2, 0x2d, 0xd5, 0x10, 0x4f, 0x73, 0x2f, 0x71, 0x66, 0xc5, 0xcc, 0xe1, 0x1c, 0x5a, 0xc, 0xc7, 0x0, 0x8d, 0xba, 0x88, 0x6d, 0x3e, 0xd3, 0x6, 0x3c, 0xa8, 0x5a, 0x67, 0x92, 0x5b, 0xc3, 0x6c, 0x8a, 0xd4, 0xb3, 0xa8, 0x56, 0x53, 0x5c, 0x9c, 0x2c, 0xac, 0xd8, 0x52, 0xb1, 0x72, 0x6a, 0x32, 0xeb, 0x5c, 0x3, 0xa2, 0x32, 0xaf, 0xe0, 0x71, 0x1a, 0x8f, 0x4f, 0xe4, 0x6c, 0xc5, 0x4b, 0xa, 0x3b, 0xe2, 0x2a, 0xb5, 0x8a, 0xa0, 0x25, 0xf6, 0xa9, 0x60, 0xd8, 0xc0, 0x4e, 0x42, 0x10, 0xf2, 0xbd, 0x22, 0x9c, 0x49, 0x85, 0x4c, 0xc6, 0xb1, 0xf0, 0x46, 0x88, 0x10, 0xa1, 0x5d, 0xa5, 0xc2, 0x6c, 0xa8, 0x57, 0xa2, 0x4c, 0xeb, 0xc1, 0xd1, 0x5c, 0x91, 0xa5, 0xb0, 0x12, 0x37, 0x62, 0x65, 0x21, 0x40, 0x4, 0xa8, 0xc3, 0x60, 0xda, 0x45, 0xab, 0x4c, 0xd0, 0x40, 0x82, 0xc4, 0x47, 0x94, 0x14, 0x29, 0xe2, 0x8c, 0x68, 0xc8, 0xa9, 0xe1, 0x1d, 0x8, 0xcc, 0x6f, 0x20, 0x7c, 0x16, 0x81, 0x4f, 0xcc, 0x8f, 0x67, 0xa9, 0x42, 0x9d, 0x63, 0x97, 0x3c, 0xae, 0x2f, 0x65, 0xb7, 0x2b, 0xe, 0x92, 0x23, 0x32, 0x1, 0xdb, 0xa6, 0x83, 0x3, 0x74, 0xca, 0xb, 0xa, 0x88, 0x1f, 0xf7, 0x0, 0x61, 0x5e, 0x8, 0x23, 0xc1, 0x2c, 0xf2, 0x5f, 0x72, 0xca, 0xe6, 0x35, 0xe6, 0x70, 0x85, 0xf4, 0x41, 0x53, 0x72, 0xfc, 0xcc, 0xe0, 0xfd, 0xcb, 0x9, 0x6c, 0x4a, 0x15, 0x67, 0xbc, 0xe2, 0x62, 0xc5, 0x42, 0xae, 0xb0, 0x38, 0xf9, 0x80, 0x1a, 0xe8, 0xb0, 0xe6, 0x88, 0xf3, 0x98, 0x56, 0x36, 0x3c, 0x57, 0x80, 0x33, 0x93, 0x2a, 0xa4, 0xb9, 0xaa, 0xbe, 0xa1, 0xc3, 0xb6, 0xa8, 0x78, 0x21, 0x4a, 0x28, 0x28, 0xa0, 0x24, 0xf2, 0xd8, 0x25, 0x7e, 0x9, 0xc7, 0xe0, 0x7f, 0x27, 0x53, 0x84, 0x7b, 0x9c, 0x7e, 0xd3, 0x99, 0xf3, 0x3a, 0x7d, 0x63, 0x9f, 0xe9, 0xc9, 0x9f, 0xf1, 0xfa, 0x9f, 0xb5, 0xfe, 0x4f, 0xfa, 0xbe, 0x67, 0xed, 0x7f, 0x98, 0xff, 0x0, 0x87, 0xd4, 0xfd, 0xaf, 0xa6, 0x4e, 0x1f, 0x24, 0xfd, 0xbf, 0xf3, 0x3f, 0xea, 0x78, 0xfa, 0xb1, 0x47, 0xfd, 0xaf, 0x12, 0x72, 0xf8, 0xff, 0x0, 0x63, 0x84, 0x87, 0xf6, 0x47, 0x34, 0x3c, 0xce, 0x1f, 0x47, 0x2f, 0xa1, 0xe2, 0x77, 0x1c, 0xbe, 0x8f, 0x28, 0xf2, 0x47, 0x87, 0xcc, 0xff, 0x0, 0x14, 0xe5, 0xf, 0xdc, 0xfa, 0x17, 0x37, 0xcf, 0xfb, 0x3f, 0x82, 0x7f, 0x7f, 0xa3, 0xfb, 0x5f, 0xe4, 0xff, 0xc4, 0x0, 0x34, 0x11, 0x0, 0x1, 0x3, 0x3, 0x2, 0x5, 0x2, 0x4, 0x4, 0x6, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x2, 0x11, 0x12, 0x21, 0x31, 0x3, 0x41, 0x10, 0x22, 0x32, 0x42, 0x51, 0x52, 0x61, 0x13, 0x62, 0x71, 0x72, 0x23, 0x81, 0x82, 0x92, 0x20, 0x33, 0x91, 0xa2, 0xb2, 0xc2, 0x4, 0x43, 0xb1, 0xff, 0xda, 0x0, 0x8, 0x1, 0x2, 0x1, 0x1, 0x3f, 0x0, 0x25, 0xd3, 0x92, 0x84, 0xf9, 0x2a, 0xfe, 0x4a, 0xbf, 0x92, 0x81, 0x28, 0x9d, 0xd0, 0x71, 0x73, 0xa3, 0xa1, 0x57, 0x0, 0x34, 0xd4, 0x61, 0xe4, 0x54, 0xce, 0xe4, 0x1e, 0x5a, 0xe7, 0x4b, 0x7a, 0x85, 0x4c, 0xa8, 0xf6, 0xad, 0x32, 0xee, 0x50, 0x47, 0xcd, 0x57, 0xca, 0x9c, 0xdf, 0x72, 0xae, 0x37, 0x28, 0x93, 0x19, 0x41, 0xc7, 0xc9, 0x52, 0x63, 0x2a, 0x4f, 0x94, 0x49, 0xf2, 0x54, 0x9f, 0x25, 0x49, 0xf2, 0x55, 0x47, 0xc9, 0x40, 0x99, 0xca, 0x93, 0xe5, 0x49, 0xf2, 0x50, 0x26, 0x77, 0x4d, 0x95, 0x2, 0x78, 0x8e, 0xe, 0x75, 0xc0, 0x4d, 0x22, 0x4d, 0x63, 0xb7, 0xf0, 0xff, 0x0, 0x4a, 0xac, 0x90, 0xc6, 0xb7, 0xf9, 0xdf, 0x13, 0xa5, 0x7, 0x4d, 0x43, 0x54, 0xd5, 0xab, 0xd0, 0xdf, 0x4a, 0x2e, 0x70, 0x22, 0xe4, 0xb1, 0x89, 0x91, 0x26, 0x1d, 0xcb, 0xdb, 0x52, 0xf2, 0x32, 0x9f, 0x1, 0x7, 0x9, 0x43, 0x8, 0xa2, 0xa1, 0x14, 0x7, 0x3, 0xc5, 0x85, 0xc, 0xa8, 0x41, 0xaa, 0x84, 0xe3, 0x9, 0xce, 0xa4, 0x14, 0x7f, 0xe4, 0x34, 0x96, 0xc8, 0xfe, 0x5d, 0xfe, 0xe4, 0x60, 0x3c, 0x3a, 0x3f, 0x17, 0x54, 0x39, 0xff, 0x0, 0xb9, 0x6, 0x97, 0x17, 0x2, 0x69, 0x72, 0x6e, 0x98, 0x36, 0x9c, 0x75, 0x20, 0xc1, 0x4, 0xd, 0x90, 0x63, 0xc1, 0x4, 0x1f, 0xdc, 0xb5, 0x9, 0x73, 0xa0, 0x61, 0x1d, 0x3a, 0x42, 0x1b, 0x22, 0x8a, 0x95, 0x28, 0x94, 0x8, 0x53, 0xc0, 0x9b, 0xa0, 0xe8, 0x70, 0x1e, 0xa4, 0xe, 0x53, 0x54, 0xc0, 0x32, 0x9e, 0xe9, 0x8b, 0xf2, 0x9b, 0x59, 0x1, 0x90, 0x7a, 0x67, 0xab, 0xec, 0x5a, 0xb1, 0xca, 0x7a, 0xbd, 0x4b, 0x51, 0x8c, 0x80, 0xe9, 0xfc, 0x96, 0x9e, 0xa0, 0x2, 0xff, 0x0, 0x88, 0xd6, 0xf4, 0xcf, 0x52, 0x96, 0x92, 0x3a, 0x7f, 0xd9, 0x75, 0xcc, 0xf, 0x15, 0x27, 0x18, 0x13, 0x11, 0xea, 0xa5, 0x13, 0x3b, 0xf5, 0x36, 0x9e, 0x62, 0x8b, 0x4d, 0x40, 0x41, 0x13, 0xdc, 0xa8, 0xa6, 0x2a, 0x26, 0x38, 0x6e, 0x9d, 0x75, 0x16, 0x45, 0x15, 0xee, 0x87, 0xd, 0xd0, 0x33, 0xa8, 0x8, 0xdb, 0x95, 0x6e, 0x53, 0xa, 0x78, 0x1b, 0xa2, 0x8, 0x10, 0x61, 0xdf, 0x2b, 0x7b, 0x90, 0xa6, 0xcd, 0x1f, 0xd5, 0xde, 0xba, 0x51, 0x26, 0xc6, 0x3, 0xbb, 0xa9, 0xfb, 0x54, 0xb4, 0x83, 0xb7, 0x86, 0xa6, 0x68, 0x47, 0x33, 0xcf, 0xda, 0xc5, 0x62, 0xf0, 0xe1, 0x6f, 0x52, 0xc5, 0xc5, 0x7d, 0x46, 0xa4, 0x64, 0xe7, 0xfa, 0x7f, 0xa2, 0xa6, 0x60, 0x89, 0xe4, 0x75, 0x3c, 0xc8, 0xc5, 0xc3, 0x91, 0x1c, 0xc1, 0xa4, 0xdb, 0x8e, 0xdc, 0x8, 0x44, 0x70, 0x18, 0xe0, 0x72, 0xb4, 0xc0, 0xf, 0x9f, 0x2a, 0x32, 0x9b, 0x64, 0x60, 0x91, 0x3f, 0x97, 0xdc, 0xa5, 0xa0, 0xcf, 0x4b, 0xdc, 0x3f, 0xb9, 0x4e, 0x1, 0x13, 0x77, 0x54, 0xd5, 0xb4, 0x43, 0xad, 0xdf, 0xf2, 0x20, 0xd2, 0x1f, 0x23, 0x13, 0x69, 0x44, 0xd4, 0x49, 0x8f, 0x7f, 0xd8, 0x81, 0x8b, 0xd2, 0x81, 0x26, 0x5c, 0xd7, 0x53, 0xcd, 0xd2, 0xef, 0x4a, 0x93, 0xea, 0x65, 0x49, 0xa4, 0x82, 0x5a, 0xd1, 0x5f, 0xa9, 0xc5, 0x73, 0x48, 0x26, 0x9a, 0x7f, 0xd9, 0x1, 0x70, 0x4f, 0x37, 0x6a, 0x71, 0xbd, 0x94, 0xa1, 0xc0, 0xa2, 0x14, 0x26, 0xf0, 0x2a, 0x79, 0x87, 0x0, 0x11, 0x12, 0x20, 0x65, 0x9, 0x4, 0xd5, 0xe, 0x73, 0x47, 0xf9, 0x20, 0xe3, 0x60, 0x5, 0x70, 0x4f, 0x32, 0x91, 0x93, 0x56, 0x22, 0x9f, 0x9d, 0x4d, 0x2f, 0x69, 0x3e, 0x26, 0xc8, 0x35, 0xd9, 0x9c, 0xf4, 0xff, 0x0, 0x9a, 0x4, 0x91, 0x7d, 0xd6, 0xbc, 0x7, 0xb, 0x4c, 0xa6, 0x9f, 0x6e, 0x55, 0xa4, 0xf6, 0x89, 0x9b, 0x23, 0x4, 0x3, 0x13, 0x1d, 0xa8, 0x0, 0x4c, 0xf4, 0xad, 0x40, 0x69, 0x8, 0x20, 0xa5, 0x4a, 0xa9, 0x14, 0x7, 0x12, 0x39, 0x9b, 0xf5, 0x43, 0x2a, 0x51, 0x91, 0x94, 0x61, 0xc4, 0xe5, 0xba, 0x8d, 0x1b, 0x77, 0x35, 0xa8, 0x12, 0x70, 0x69, 0xa9, 0xd5, 0x39, 0xc8, 0xf5, 0x5c, 0x97, 0x39, 0x9c, 0xac, 0xa4, 0x20, 0xd8, 0x82, 0x7a, 0xe7, 0x75, 0x4e, 0xf9, 0x52, 0x4c, 0x8e, 0x9a, 0x7c, 0x74, 0xad, 0x4b, 0x67, 0xb9, 0x1, 0x64, 0xd2, 0x30, 0x51, 0x2d, 0x17, 0x32, 0x81, 0x7, 0x1c, 0xbf, 0x72, 0x27, 0x96, 0xe8, 0xd9, 0x54, 0xa6, 0x78, 0x5, 0xb2, 0x18, 0x47, 0x80, 0x18, 0x2a, 0x2e, 0x9b, 0x48, 0xb9, 0x29, 0xef, 0x69, 0x9, 0x90, 0x5c, 0x7d, 0x51, 0x95, 0x51, 0xaa, 0x91, 0xca, 0xe1, 0xd4, 0xe6, 0xa2, 0xdb, 0xdb, 0xb9, 0x11, 0xed, 0x8, 0x63, 0x75, 0x36, 0x81, 0x2e, 0x7a, 0x73, 0x6a, 0x9b, 0x3a, 0xb0, 0x7f, 0xb5, 0x50, 0xf1, 0x2, 0x15, 0xe, 0x0, 0x92, 0x36, 0x41, 0xae, 0x80, 0x26, 0x14, 0x1b, 0x6f, 0x4e, 0x11, 0x69, 0x30, 0x4f, 0xea, 0x5a, 0x8d, 0x9c, 0x76, 0x84, 0xe6, 0x91, 0xc4, 0x2b, 0x42, 0xb, 0x2a, 0x1a, 0xaa, 0x92, 0x4, 0x45, 0x28, 0xb8, 0xaa, 0x8a, 0x92, 0x98, 0xea, 0x4c, 0x94, 0x28, 0x6e, 0x98, 0x23, 0xbd, 0xb, 0x84, 0x40, 0xdc, 0x2f, 0xa2, 0x6a, 0xa6, 0xf2, 0x2c, 0x7e, 0x55, 0x9f, 0x65, 0x72, 0x7d, 0x82, 0x22, 0x11, 0xb6, 0xe9, 0xa3, 0x2d, 0x3f, 0x72, 0x61, 0x17, 0x9, 0xcd, 0x91, 0x0, 0x59, 0x39, 0xa5, 0xaa, 0x50, 0x4d, 0xd1, 0x76, 0xeb, 0xe1, 0x18, 0xca, 0x2c, 0x23, 0x65, 0xba, 0x19, 0x11, 0xe5, 0x58, 0x9c, 0xa8, 0x6a, 0xe5, 0x46, 0x36, 0x4d, 0xc, 0x2c, 0x69, 0x3f, 0xf5, 0xa2, 0xe1, 0x51, 0x3, 0xc4, 0xd9, 0x2, 0x4a, 0x2d, 0x4e, 0x3e, 0x10, 0x79, 0x88, 0x28, 0x3a, 0x91, 0x75, 0x56, 0xe1, 0x34, 0xce, 0x4d, 0xd1, 0x31, 0x31, 0xcc, 0xf5, 0x55, 0x81, 0xcb, 0xbb, 0x90, 0x69, 0x99, 0x88, 0x5b, 0x27, 0x2, 0x76, 0x5a, 0xba, 0x45, 0xa6, 0xc7, 0x2b, 0x43, 0x4f, 0x24, 0xdf, 0xf8, 0x1c, 0xc0, 0x42, 0x88, 0x70, 0xfa, 0xaa, 0x5d, 0x3d, 0x28, 0xe9, 0x6a, 0x6c, 0x2, 0xf8, 0x5a, 0x9b, 0xc0, 0x43, 0x40, 0xee, 0xe4, 0x74, 0x60, 0x11, 0x55, 0xd3, 0x74, 0x98, 0xd0, 0x64, 0xfe, 0xa5, 0xa5, 0x6, 0x4c, 0x94, 0x30, 0x53, 0xbe, 0x8a, 0x4a, 0x17, 0x30, 0x80, 0x2d, 0x12, 0x0, 0x46, 0xa7, 0x0, 0x40, 0x8, 0x39, 0xd3, 0xd3, 0x1d, 0xb5, 0x2a, 0x7c, 0x18, 0x55, 0x10, 0xe8, 0x9a, 0xa5, 0xc, 0x70, 0x73, 0x65, 0x36, 0x1b, 0x6c, 0x2a, 0x9b, 0xe5, 0x56, 0x38, 0xbc, 0xa, 0xc2, 0x76, 0xab, 0xa6, 0xc2, 0x11, 0xd4, 0x7f, 0x90, 0x13, 0x9c, 0xe3, 0x97, 0x2b, 0xfc, 0xca, 0x8d, 0x43, 0x71, 0x3f, 0xa9, 0x4e, 0xa1, 0x10, 0x40, 0xf0, 0x8f, 0x23, 0x31, 0x4b, 0x93, 0x44, 0x4b, 0x89, 0xe, 0x94, 0xc, 0xc1, 0x23, 0x95, 0x12, 0xf, 0x6c, 0xc2, 0x13, 0x22, 0xd0, 0x83, 0x8c, 0xd2, 0x77, 0x41, 0x80, 0x97, 0xa, 0xa2, 0x10, 0x71, 0x30, 0xd1, 0xdb, 0xd4, 0xaf, 0x39, 0xa5, 0x3c, 0x86, 0xbb, 0x32, 0xe4, 0xdd, 0x40, 0xe4, 0x6c, 0x89, 0x84, 0x61, 0x40, 0x50, 0x21, 0x1, 0x17, 0xe0, 0x4f, 0x37, 0xe6, 0x89, 0xca, 0x85, 0x5, 0x4b, 0xbc, 0xa9, 0x74, 0x45, 0x45, 0x69, 0x97, 0x19, 0x12, 0x54, 0x2, 0xe1, 0x24, 0xea, 0xb5, 0x4b, 0x79, 0x8d, 0x27, 0xe5, 0x40, 0x16, 0x36, 0xff, 0x0, 0xb5, 0x34, 0x5b, 0xee, 0x4e, 0xff, 0x0, 0xc4, 0xe9, 0x96, 0x97, 0x45, 0x28, 0xd3, 0x32, 0x1a, 0x7d, 0xd3, 0xb3, 0x23, 0x95, 0x13, 0x25, 0x3c, 0x73, 0x14, 0xc, 0x1b, 0x26, 0xbe, 0x44, 0x14, 0xf1, 0x64, 0x2e, 0x11, 0x8, 0x94, 0x4, 0x99, 0x4f, 0x7c, 0xb, 0x65, 0xe, 0xa1, 0xf5, 0x44, 0x5c, 0xa0, 0x14, 0x70, 0x84, 0xdb, 0x1b, 0x26, 0x82, 0xe, 0x7a, 0xf2, 0x1a, 0x8c, 0xe0, 0x18, 0x8, 0xdf, 0xed, 0x4d, 0xb4, 0x9, 0x95, 0xa9, 0x64, 0x44, 0xc1, 0x69, 0xc7, 0xa9, 0x49, 0xcf, 0xe5, 0x85, 0x1e, 0xf2, 0xa9, 0xd, 0xb9, 0x4e, 0x82, 0x65, 0x40, 0x57, 0x55, 0x3b, 0xca, 0xf, 0x21, 0x7c, 0x55, 0xf1, 0x47, 0x84, 0xe7, 0x93, 0xec, 0x8a, 0x19, 0x1f, 0x54, 0x72, 0x84, 0x7f, 0xb, 0x62, 0x3d, 0xf8, 0xd, 0xd3, 0x62, 0x2c, 0x8d, 0x53, 0x74, 0xd9, 0xdb, 0x8, 0xcd, 0xb8, 0x3d, 0x5, 0x65, 0x6e, 0x36, 0xe0, 0xec, 0xdb, 0x80, 0xc8, 0xfa, 0xaf, 0xff, 0xc4, 0x0, 0x2a, 0x11, 0x0, 0x2, 0x1, 0x3, 0x4, 0x0, 0x5, 0x4, 0x3, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x11, 0x2, 0x21, 0x31, 0x10, 0x12, 0x41, 0x51, 0x3, 0x20, 0x22, 0x32, 0x61, 0x42, 0x52, 0x62, 0x81, 0x13, 0x71, 0x72, 0xb1, 0xff, 0xda, 0x0, 0x8, 0x1, 0x3, 0x1, 0x1, 0x3f, 0x0, 0x85, 0x18, 0x1c, 0x74, 0x7e, 0x8f, 0xd0, 0xd5, 0xb4, 0x84, 0x97, 0x66, 0xdb, 0xb6, 0xbe, 0xd1, 0xd2, 0xaa, 0x4a, 0xfe, 0xdf, 0x71, 0x52, 0x57, 0x69, 0x89, 0xc1, 0x62, 0x17, 0x43, 0x56, 0x22, 0xe4, 0x21, 0x24, 0x42, 0xe8, 0x49, 0x74, 0x34, 0xba, 0x2c, 0x28, 0x3f, 0x5a, 0x38, 0x27, 0xca, 0x95, 0xa4, 0x73, 0x68, 0xef, 0xd4, 0x6d, 0xcb, 0x7e, 0xcd, 0xa3, 0x51, 0x1b, 0x6d, 0x49, 0x9, 0xcd, 0xbd, 0x4c, 0xab, 0xfa, 0xd2, 0x93, 0x81, 0x88, 0x5e, 0x46, 0x2d, 0x6a, 0x43, 0xc6, 0x92, 0x6e, 0x10, 0xae, 0x7f, 0x1b, 0xbf, 0xe4, 0x27, 0x29, 0xa7, 0xec, 0xa7, 0xd2, 0x37, 0x9, 0x31, 0xd5, 0xcc, 0xd, 0xf2, 0xc6, 0xe9, 0x68, 0xa5, 0x6d, 0x52, 0xcd, 0xd2, 0xc6, 0x21, 0xc, 0x82, 0x6, 0x88, 0x27, 0x46, 0xac, 0xde, 0x8d, 0x58, 0x86, 0x53, 0x4c, 0x27, 0x61, 0xb2, 0x8e, 0x44, 0xdc, 0xc1, 0x55, 0x33, 0x75, 0x62, 0xe6, 0x39, 0x17, 0xf6, 0x25, 0x17, 0xfb, 0x59, 0xb9, 0x43, 0x72, 0x4c, 0xe3, 0x44, 0x26, 0x4e, 0x88, 0x63, 0xd1, 0x60, 0x6a, 0x28, 0x69, 0xf2, 0x70, 0x31, 0x7c, 0x12, 0x9f, 0xc0, 0xe7, 0x3f, 0xf0, 0x85, 0x71, 0x26, 0x8a, 0xab, 0xe1, 0xe, 0xd4, 0xc1, 0x9e, 0xb0, 0x5a, 0x49, 0x4a, 0xcf, 0xea, 0x17, 0x10, 0x5a, 0x27, 0xca, 0x84, 0x31, 0xe7, 0x45, 0x82, 0xa6, 0xdd, 0x31, 0xa3, 0x11, 0x12, 0xbf, 0x12, 0x33, 0x1f, 0x8d, 0xce, 0x72, 0x37, 0x6b, 0x98, 0xe4, 0xcf, 0x23, 0x51, 0x12, 0xb8, 0x21, 0x74, 0xc6, 0x94, 0x4b, 0x14, 0x71, 0x23, 0xe9, 0x9, 0x76, 0x41, 0x1e, 0x57, 0xaf, 0xf, 0x54, 0xe1, 0x9c, 0x28, 0x36, 0xa9, 0x6d, 0xb8, 0xc1, 0x1c, 0x28, 0x1d, 0xd3, 0x81, 0xb4, 0x34, 0x78, 0x72, 0xd0, 0xca, 0xd3, 0x62, 0x95, 0x61, 0xdb, 0xe4, 0xa2, 0x24, 0x63, 0x64, 0x33, 0x69, 0xb4, 0xbc, 0x8f, 0x3a, 0xac, 0x3d, 0x64, 0x56, 0x4b, 0xec, 0xa8, 0x85, 0xca, 0xc1, 0xc7, 0xdb, 0xbb, 0xb2, 0x6f, 0x4, 0xdc, 0x84, 0x25, 0x61, 0xe9, 0x71, 0xb6, 0x2c, 0x89, 0xc9, 0xb5, 0x79, 0x39, 0x2a, 0xce, 0xb3, 0xa3, 0x9e, 0x5, 0x4b, 0x2a, 0x94, 0x90, 0xd5, 0xa5, 0xf2, 0x2a, 0xbb, 0x33, 0xa4, 0x5f, 0xf1, 0x26, 0x3f, 0xc8, 0xda, 0x25, 0x61, 0x31, 0xb4, 0x4a, 0xe4, 0x9e, 0x8a, 0x2a, 0x81, 0x34, 0xf5, 0x64, 0x36, 0xc6, 0xb5, 0x81, 0x24, 0x5b, 0x4a, 0x94, 0xa1, 0xee, 0xaa, 0xa8, 0x7f, 0x48, 0xd0, 0x89, 0x1e, 0x9, 0xb4, 0x31, 0x55, 0x13, 0x37, 0x17, 0x24, 0xe8, 0xfb, 0x1a, 0x29, 0xaa, 0xa, 0x6a, 0x95, 0xa3, 0xb1, 0x57, 0x88, 0xb8, 0x37, 0xf6, 0x6e, 0x5a, 0x33, 0x82, 0x75, 0x9a, 0x95, 0x4e, 0x3e, 0xa1, 0x27, 0x12, 0xc7, 0x62, 0x44, 0xbb, 0x36, 0xde, 0x47, 0x4c, 0x9b, 0x7b, 0x1a, 0xe8, 0x8e, 0xf0, 0x47, 0x3, 0x76, 0x81, 0x31, 0x55, 0x18, 0x29, 0xf1, 0x14, 0x4c, 0x60, 0xf1, 0x2b, 0x94, 0xb8, 0x9f, 0x22, 0x6d, 0x1c, 0x1b, 0x94, 0x65, 0x1b, 0xe8, 0xec, 0xfe, 0x4a, 0x7, 0xe2, 0xf4, 0x85, 0xe2, 0xdd, 0x58, 0xaa, 0xb6, 0xdd, 0x8a, 0xf4, 0x5a, 0x32, 0x53, 0xb0, 0xa1, 0x5a, 0x48, 0x5d, 0x93, 0xd9, 0x12, 0x88, 0x12, 0x62, 0xab, 0xa1, 0xdc, 0xda, 0xcd, 0xaf, 0x5a, 0x70, 0x2f, 0xd, 0x72, 0xc5, 0x45, 0x3f, 0x22, 0xa6, 0x9e, 0x8f, 0x4f, 0xc1, 0xba, 0x85, 0xd1, 0xe8, 0xca, 0x66, 0x58, 0xef, 0x64, 0x88, 0xe0, 0xc7, 0x23, 0x23, 0x91, 0xbc, 0x38, 0x23, 0x2c, 0xfd, 0x14, 0xa9, 0x45, 0x54, 0xc1, 0x4, 0x68, 0x9b, 0x25, 0x8d, 0xe8, 0x95, 0x8e, 0x9, 0x44, 0xa2, 0x29, 0xe8, 0x8a, 0x7a, 0x2a, 0x85, 0x78, 0x1b, 0xb5, 0x96, 0xd9, 0x2f, 0x6b, 0x93, 0x38, 0x19, 0x48, 0xa2, 0xf0, 0x5e, 0x2e, 0xc5, 0x8c, 0x98, 0x29, 0xc0, 0xe1, 0x8e, 0x98, 0x10, 0xf4, 0x48, 0x78, 0x82, 0x9a, 0x4e, 0x9, 0xb1, 0x24, 0xea, 0xd4, 0x8f, 0x2, 0x81, 0xc, 0xa5, 0x49, 0xf0, 0xd1, 0x8, 0x92, 0xec, 0x56, 0x27, 0x48, 0x46, 0xd4, 0x6c, 0x46, 0xc1, 0x53, 0x1a, 0x70, 0xcb, 0x40, 0xc5, 0xab, 0x1c, 0xe8, 0xf4, 0xb7, 0x3, 0x14, 0xc, 0xa0, 0x65, 0xfc, 0xa8, 0x43, 0x1c, 0xc1, 0xff, 0xd9, 0x12, 0x3d, 0x31, 0x2c, 0x41, 0x4d, 0x0, 0x0, 0x0, 0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0xed, 0x7d, 0x6b, 0x8f, 0x23, 0xb9, 0x91, 0xe0, 0x5f, 0x91, 0x7b, 0x30, 0xf0, 0xb4, 0x4b, 0x52, 0xa7, 0x9e, 0xd5, 0x95, 0xc2, 0x14, 0xbc, 0xd8, 0xfb, 0xb0, 0x7, 0xac, 0xfd, 0xe5, 0xee, 0xc3, 0x1, 0xe3, 0x3e, 0x20, 0x25, 0xa5, 0x4a, 0xe9, 0x49, 0x3d, 0x56, 0x99, 0xea, 0xc7, 0x8, 0xda, 0xdf, 0x7e, 0x7c, 0x33, 0x48, 0x46, 0x90, 0x29, 0x55, 0xb5, 0xed, 0x3, 0xc6, 0xed, 0xe9, 0x4e, 0x31, 0x82, 0xc1, 0x60, 0x30, 0x18, 0xc1, 0x67, 0x70, 0xdb, 0xee, 0xea, 0xcb, 0xe6, 0xb0, 0x6f, 0x7, 0x9b, 0x62, 0x57, 0xd5, 0xdf, 0xf2, 0xa6, 0xd8, 0x37, 0x83, 0xa6, 0x3c, 0x55, 0x9b, 0xc5, 0x60, 0xd7, 0xc, 0xda, 0xf2, 0x6b, 0x3b, 0x68, 0xaa, 0xdf, 0xca, 0x41, 0xb1, 0xfe, 0xfb, 0xb9, 0x69, 0xf3, 0x51, 0x96, 0xfd, 0xb8, 0x18, 0x7c, 0x29, 0x97, 0xbf, 0x56, 0x2d, 0xe, 0xbd, 0x2e, 0xf, 0xeb, 0x6f, 0x97, 0x5d, 0x71, 0x7a, 0xa9, 0xf6, 0x79, 0x76, 0x2d, 0x4e, 0x6d, 0xb5, 0xaa, 0xcb, 0x7e, 0xd1, 0x54, 0xeb, 0xb2, 0xbf, 0x2e, 0xdb, 0xa2, 0xaa, 0x9b, 0xfe, 0xa6, 0x7a, 0x59, 0x15, 0xc7, 0xb6, 0x3a, 0xec, 0xf9, 0xe7, 0xf9, 0x54, 0xf6, 0x37, 0x87, 0x43, 0x5b, 0x9e, 0xfa, 0xdb, 0xb2, 0x58, 0xf3, 0x7f, 0x5e, 0x4e, 0x87, 0xf3, 0xb1, 0xbf, 0x2b, 0xaa, 0x7d, 0x7f, 0x57, 0xee, 0xcf, 0xfd, 0x7d, 0xf1, 0xb9, 0xdf, 0x94, 0x2b, 0x91, 0xa3, 0x39, 0xef, 0x18, 0xf9, 0x6f, 0x97, 0x75, 0xd5, 0x1c, 0xeb, 0xe2, 0x5b, 0xbe, 0xac, 0xf, 0xab, 0x5f, 0xaf, 0xc5, 0x79, 0x5d, 0x1d, 0xfa, 0xab, 0x62, 0xff, 0xb9, 0x68, 0xfa, 0xc7, 0xd3, 0xe1, 0xe5, 0x54, 0x36, 0x4d, 0xff, 0x33, 0x2b, 0xf5, 0x60, 0x30, 0xab, 0x7d, 0x5d, 0xed, 0xcb, 0x81, 0xc8, 0xb0, 0xf8, 0x5c, 0x72, 0xd6, 0x8a, 0x7a, 0x50, 0xd4, 0xd5, 0xcb, 0x3e, 0x5f, 0x16, 0x4d, 0xc9, 0xa1, 0x92, 0x50, 0xbe, 0x3f, 0xb4, 0x3f, 0xfd, 0xb2, 0x62, 0x92, 0x39, 0x1d, 0xea, 0xe6, 0xd3, 0x7b, 0x43, 0x62, 0x7f, 0xd8, 0x97, 0x8b, 0x6d, 0x59, 0xbd, 0x6c, 0x5b, 0x56, 0xbb, 0x5f, 0xb6, 0xd5, 0x7a, 0x5d, 0xee, 0x3f, 0xf5, 0xdb, 0x72, 0xc7, 0xc0, 0x6d, 0xe9, 0xe0, 0x5d, 0x8b, 0xcb, 0xb2, 0x58, 0xfd, 0xca, 0xeb, 0xb2, 0x5f, 0xf, 0x56, 0x87, 0xfa, 0x70, 0xca, 0xdb, 0x13, 0x93, 0xf0, 0xb1, 0x38, 0x95, 0xfb, 0xf6, 0x5a, 0xe4, 0x5, 0xab, 0xd1, 0x67, 0x26, 0x9c, 0x7c, 0x7b, 0x60, 0xec, 0x5c, 0xe, 0xe7, 0x96, 0xb3, 0xc0, 0x8, 0x2f, 0xfb, 0xd, 0x2b, 0x79, 0xff, 0x22, 0x1b, 0xe7, 0x8b, 0x2c, 0xef, 0x31, 0xcb, 0xae, 0xeb, 0xcd, 0x5e, 0xa6, 0x35, 0xed, 0xb7, 0xba, 0xcc, 0xab, 0x96, 0x71, 0xbf, 0xba, 0x6e, 0x47, 0x5a, 0xe2, 0xc3, 0xf9, 0x63, 0xb9, 0xeb, 0x65, 0x57, 0xf6, 0xf3, 0x57, 0x50, 0x7a, 0xfe, 0xc3, 0x66, 0x93, 0x2d, 0x24, 0xb, 0x3f, 0x64, 0x8c, 0x4e, 0x73, 0x66, 0x45, 0x9c, 0x8f, 0x8a, 0x16, 0x6b, 0xc3, 0xfc, 0x71, 0xf6, 0xe3, 0x42, 0x88, 0x47, 0xd7, 0x6e, 0x71, 0x3c, 0x34, 0x15, 0x97, 0x78, 0x7e, 0x2a, 0x59, 0xdd, 0x18, 0xa3, 0xa4, 0xcc, 0x38, 0xa5, 0xf6, 0x70, 0xcc, 0x7, 0xc3, 0x59, 0xb9, 0xe3, 0xb4, 0x2f, 0xcb, 0x43, 0xdb, 0x1e, 0x76, 0x2c, 0x61, 0xcc, 0x53, 0xaa, 0xdd, 0xb, 0x4b, 0x39, 0xb1, 0xa6, 0x65, 0x75, 0x6b, 0x3e, 0xbf, 0x8, 0xf1, 0xe6, 0x27, 0xd6, 0xe6, 0xef, 0x2f, 0xbc, 0xe6, 0x9b, 0xfa, 0xf0, 0x25, 0x97, 0xb2, 0xbc, 0x6e, 0x4f, 0x97, 0xc1, 0xee, 0xf0, 0xdb, 0x60, 0x79, 0xf8, 0xca, 0x19, 0xab, 0xf6, 0x2f, 0x39, 0x6f, 0x7, 0x26, 0x30, 0x9e, 0x64, 0x94, 0x8f, 0x0, 0x13, 0xc9, 0xa6, 0xc5, 0x8e, 0xa7, 0xd2, 0x96, 0x58, 0x9c, 0xdb, 0xc3, 0x75, 0x75, 0x60, 0x8a, 0xf9, 0xeb, 0x72, 0xcd, 0x94, 0xa6, 0xec, 0x37, 0xc5, 0xe, 0xca, 0x64, 0xc4, 0x78, 0x5f, 0x9e, 0x59, 0x4d, 0xf6, 0xfd, 0x6a, 0x7f, 0x3c, 0xb7, 0xfd, 0xc3, 0xb1, 0x95, 0xaa, 0xc9, 0x2a, 0xce, 0xd4, 0xb1, 0xcf, 0xbb, 0x0, 0x6b, 0xcc, 0xe2, 0x22, 0x45, 0x5b, 0xed, 0xb7, 0xac, 0xef, 0xb4, 0xb, 0x4e, 0xc1, 0xfc, 0x30, 0x7d, 0x41, 0x52, 0xb2, 0xc5, 0x7f, 0xae, 0x9a, 0x6a, 0x59, 0x97, 0xba, 0x4, 0x49, 0xf2, 0x22, 0x7a, 0x95, 0x50, 0x93, 0xcd, 0xe1, 0xb4, 0x93, 0x8a, 0xa4, 0x30, 0xb6, 0xac, 0xbb, 0xf6, 0x4, 0x23, 0xbf, 0xb4, 0xdf, 0x8e, 0xe5, 0xcf, 0x32, 0xf9, 0x53, 0x1f, 0x24, 0x31, 0xad, 0x2f, 0x5b, 0x27, 0x85, 0xb5, 0xc6, 0xae, 0x6a, 0x3f, 0x5d, 0xb4, 0xe0, 0x8a, 0xe3, 0xb1, 0x2c, 0x18, 0xf9, 0x55, 0x99, 0xcb, 0xfc, 0x8b, 0xd5, 0xf9, 0xd4, 0x30, 0xe6, 0x8f, 0x87, 0x8a, 0x9, 0xec, 0xa4, 0xa, 0xfb, 0x85, 0x69, 0x72, 0xc1, 0xb8, 0x5b, 0x7f, 0x82, 0xc5, 0x9a, 0xc4, 0x8b, 0xca, 0xb4, 0x2e, 0x37, 0xc5, 0xb9, 0x6e, 0x55, 0xa6, 0x3c, 0x17, 0x4d, 0xb7, 0x39, 0xac, 0xce, 0xcd, 0xa0, 0xda, 0xef, 0x59, 0x57, 0x16, 0xf9, 0xc2, 0x74, 0xa3, 0xe, 0x8b, 0x63, 0xb1, 0x5e, 0xf3, 0xe6, 0xca, 0xae, 0x80, 0xe9, 0xd5, 0xb6, 0x5c, 0xfd, 0xca, 0x1a, 0xce, 0xad, 0x5b, 0xc1, 0x7a, 0xa6, 0xad, 0x8, 0x68, 0x6a, 0x49, 0x4c, 0xea, 0x87, 0xa7, 0x3b, 0x0, 0x84, 0xa7, 0xa2, 0xe5, 0xef, 0xcf, 0xbb, 0x65, 0x79, 0xfa, 0xc4, 0xf8, 0x56, 0x85, 0x9, 0xa6, 0x7, 0xcd, 0xb1, 0xda, 0xf, 0xa0, 0x42, 0x10, 0xd8, 0xac, 0x23, 0xbb, 0xd8, 0x17, 0xa5, 0x80, 0x42, 0xe3, 0x60, 0xe3, 0xb0, 0xa6, 0x58, 0x6d, 0x41, 0x4e, 0x99, 0x30, 0x58, 0xf1, 0xf6, 0xa9, 0x91, 0xa2, 0xa8, 0xc, 0xeb, 0x72, 0x75, 0x38, 0x15, 0xbc, 0xb7, 0x62, 0xd, 0x2d, 0x94, 0xc8, 0xe8, 0xaa, 0xab, 0xff, 0x5a, 0xa5, 0x3, 0x53, 0xd3, 0xf2, 0x96, 0x56, 0xed, 0xc4, 0xad, 0x57, 0x5d, 0x1c, 0x9b, 0x32, 0xd7, 0x1f, 0xb, 0x5, 0x60, 0xc6, 0x6c, 0x25, 0xc5, 0xd7, 0xae, 0xfb, 0xed, 0xf6, 0x62, 0xc5, 0xf9, 0xe1, 0x4f, 0x7f, 0xe8, 0xfd, 0xaf, 0xc3, 0xf9, 0xc4, 0xca, 0xef, 0x6d, 0xdb, 0xf6, 0xd8, 0xe4, 0x1f, 0x3e, 0xbc, 0x54, 0xed, 0xf6, 0xbc, 0x1c, 0xae, 0xe, 0xbb, 0xf, 0xdb, 0xd9, 0xf2, 0xf8, 0x81, 0xab, 0xd6, 0x8c, 0x35, 0x43, 0x55, 0x97, 0x27, 0x61, 0x40, 0x3f, 0x30, 0xe3, 0xbc, 0xfc, 0xb0, 0x2b, 0x1a, 0x26, 0xc0, 0xf, 0xcd, 0x69, 0xf5, 0x61, 0xd5, 0x34, 0x1f, 0xb8, 0x1f, 0x18, 0xb2, 0x8f, 0xde, 0x9f, 0x3e, 0xfc, 0x79, 0x57, 0xae, 0xab, 0xa2, 0x77, 0x3c, 0x31, 0x5d, 0xbd, 0xfc, 0xa9, 0x9f, 0x17, 0x1b, 0xee, 0x36, 0xf2, 0x65, 0xc9, 0x3a, 0x4b, 0x9, 0xd, 0x5e, 0xd6, 0xcb, 0xfe, 0x50, 0xed, 0x8e, 0x87, 0x53, 0x5b, 0xec, 0x5b, 0x60, 0xf9, 0x40, 0xa2, 0xa3, 0x48, 0xdb, 0x62, 0xcd, 0x24, 0xc2, 0x5, 0x5, 0x30, 0x68, 0x88, 0xf4, 0x7d, 0x18, 0xe8, 0x5a, 0x30, 0x7b, 0xce, 0xbb, 0x76, 0x5b, 0xae, 0x65, 0x67, 0xb6, 0x6d, 0x93, 0x33, 0xce, 0xca, 0x93, 0x74, 0x33, 0xbf, 0x6c, 0x4f, 0xe5, 0xe6, 0x93, 0xac, 0xc0, 0x45, 0xd9, 0xaa, 0xfc, 0x5d, 0xef, 0xa7, 0x77, 0xbd, 0xa2, 0x6d, 0x4f, 0x3f, 0x71, 0xe8, 0xfb, 0xde, 0xbb, 0xf7, 0xef, 0xae, 0xc5, 0x72, 0x79, 0xfa, 0xa5, 0xad, 0xda, 0xba, 0xa4, 0xb1, 0x5, 0x58, 0xa1, 0xb, 0xc2, 0xff, 0xf7, 0xe7, 0x77, 0x7f, 0x2f, 0x98, 0x2b, 0x5c, 0x9d, 0xaa, 0x23, 0x43, 0x54, 0x39, 0xfb, 0x6, 0xf8, 0xc3, 0xbb, 0x80, 0xd8, 0xbb, 0xab, 0x70, 0x8c, 0xff, 0x75, 0x66, 0x9e, 0x98, 0x1b, 0x43, 0xdd, 0x45, 0x47, 0xc7, 0xaf, 0xbd, 0xe6, 0x50, 0x57, 0xeb, 0xde, 0xf, 0x4f, 0x4f, 0x4f, 0xac, 0xbf, 0xbc, 0x30, 0x17, 0xca, 0xf4, 0xe8, 0x57, 0xd6, 0x29, 0xb8, 0x57, 0xcf, 0x8b, 0xcf, 0x87, 0x6a, 0x7d, 0x6d, 0xb9, 0xef, 0x36, 0xfe, 0x4f, 0x28, 0xcf, 0x40, 0xba, 0xf3, 0x81, 0xd0, 0x2f, 0xee, 0x4, 0xfa, 0xed, 0xe9, 0x42, 0xe5, 0xe7, 0x3e, 0x62, 0x57, 0x7c, 0x1d, 0x7c, 0xa9, 0xd6, 0xed, 0x56, 0xc, 0x25, 0x80, 0x4c, 0xb7, 0xe3, 0xfe, 0x76, 0xd2, 0x3f, 0x5e, 0xe, 0xa7, 0xe3, 0x96, 0x59, 0xc6, 0x7c, 0xb2, 0x60, 0x68, 0x87, 0x2f, 0xec, 0x43, 0x82, 0x20, 0x55, 0x51, 0x2d, 0x45, 0x54, 0xd9, 0x54, 0xd7, 0x11, 0x6e, 0x0, 0xe1, 0x21, 0x1b, 0x59, 0x2c, 0x8b, 0x93, 0xeb, 0xb7, 0x87, 0xcb, 0x76, 0xff, 0x3c, 0x5c, 0xb1, 0xce, 0xd2, 0xf6, 0x87, 0xeb, 0xd3, 0xe1, 0x78, 0x3e, 0x3e, 0x83, 0x34, 0xdd, 0x27, 0x98, 0xc7, 0x1b, 0x60, 0x8a, 0x75, 0x1d, 0xd6, 0xc5, 0xb2, 0xac, 0x11, 0xf9, 0x71, 0xcf, 0x3b, 0x8c, 0xf7, 0x2b, 0x48, 0x46, 0x60, 0xf6, 0x58, 0xbf, 0xd2, 0x5f, 0xdb, 0x70, 0x40, 0xe1, 0xd7, 0x47, 0xa, 0x5e, 0x52, 0x2f, 0xd7, 0x36, 0x33, 0x48, 0xda, 0x22, 0x9c, 0xad, 0xd7, 0x6b, 0x40, 0xe5, 0x1a, 0xf4, 0xac, 0xb7, 0x35, 0xba, 0xd7, 0xad, 0x19, 0x78, 0x4a, 0x3f, 0x9b, 0x1d, 0xad, 0x67, 0x6f, 0x8b, 0xe3, 0x60, 0xcb, 0xac, 0x50, 0xcd, 0x2d, 0x11, 0x32, 0x6c, 0x12, 0x3, 0x4c, 0x38, 0x68, 0xfd, 0xcf, 0xa2, 0x3d, 0xf4, 0xdf, 0xfd, 0x47, 0x59, 0x7f, 0x2e, 0xf9, 0xe8, 0xa4, 0xf7, 0xd7, 0xf2, 0x5c, 0xbe, 0xeb, 0x9b, 0xdf, 0xfd, 0x7f, 0x3b, 0x55, 0x45, 0xdd, 0x7, 0x43, 0x5b, 0x50, 0xf0, 0x8c, 0x15, 0xc, 0x47, 0x3d, 0xa3, 0xe1, 0x74, 0xfc, 0x71, 0xf6, 0x38, 0x9a, 0x4e, 0xb4, 0xcd, 0x28, 0x97, 0xfc, 0xcf, 0x22, 0x14, 0xfc, 0x78, 0x39, 0x29, 0x67, 0x99, 0x3b, 0x3e, 0xf0, 0x87, 0x5, 0x90, 0x4d, 0x38, 0x38, 0x90, 0xa5, 0xeb, 0x14, 0xc8, 0x80, 0x4a, 0xbb, 0xea, 0x21, 0xc5, 0xf, 0xeb, 0xcd, 0xfc, 0x69, 0x54, 0x2c, 0x7c, 0x4b, 0x22, 0x7, 0x98, 0xb9, 0x70, 0xa9, 0x66, 0x0, 0x19, 0xcf, 0x2, 0x8c, 0x8f, 0xcc, 0x67, 0x6, 0x9c, 0x6b, 0x36, 0x5a, 0x13, 0x9a, 0x51, 0xed, 0x17, 0x3a, 0x4d, 0x37, 0x87, 0x74, 0xda, 0xcc, 0xde, 0xbe, 0xc8, 0x8a, 0xf7, 0xb8, 0xd7, 0xe8, 0x71, 0xb9, 0x29, 0xcc, 0xc1, 0x61, 0xb3, 0x61, 0x83, 0x8e, 0x7c, 0x30, 0x3e, 0x7e, 0xbd, 0xca, 0xe1, 0xbc, 0x1d, 0xff, 0xf3, 0x5e, 0xed, 0x8d, 0x1a, 0x77, 0x6c, 0x9c, 0xc7, 0x46, 0x3d, 0xbc, 0x2f, 0x1d, 0xce, 0x4c, 0x60, 0xd2, 0xb7, 0x3e, 0xf, 0x99, 0xc1, 0xdc, 0x3d, 0x17, 0xcf, 0xdc, 0x4c, 0xe0, 0x30, 0x1, 0x61, 0x7f, 0xd, 0xd8, 0x20, 0xe7, 0x78, 0x60, 0xb6, 0x83, 0xd, 0x9d, 0x87, 0xcc, 0x9f, 0xec, 0x96, 0x7b, 0x36, 0xab, 0xe8, 0xa9, 0xac, 0x26, 0x81, 0xff, 0x74, 0x27, 0x9, 0xb, 0xd7, 0xbe, 0x2c, 0xa0, 0x53, 0x96, 0x84, 0x79, 0xfb, 0x32, 0xb3, 0xad, 0x34, 0x95, 0xf, 0x38, 0xce, 0xd, 0xab, 0x85, 0x0, 0x1a, 0xc2, 0xc6, 0xc7, 0x4d, 0x69, 0xe5, 0xa1, 0xd4, 0x65, 0x81, 0x76, 0xbd, 0x85, 0x57, 0xa0, 0xed, 0xb, 0x5c, 0xef, 0xe5, 0x20, 0xbc, 0xa8, 0xeb, 0xde, 0x70, 0xdc, 0xf4, 0x4a, 0x36, 0xe8, 0x66, 0x62, 0xe1, 0x63, 0x8c, 0xc5, 0xe0, 0x90, 0xc2, 0x48, 0x80, 0xd1, 0x99, 0x51, 0x4a, 0x4a, 0xab, 0xea, 0xb4, 0xb2, 0x16, 0x4c, 0xf1, 0x3c, 0x63, 0x53, 0x3f, 0x36, 0x74, 0x97, 0xd, 0xcf, 0x4d, 0x63, 0x3e, 0x66, 0x75, 0x54, 0x83, 0xdf, 0x81, 0x9a, 0xe, 0x88, 0x24, 0x33, 0xf2, 0xb3, 0x66, 0x14, 0x8a, 0x63, 0xf6, 0x34, 0x2f, 0x1e, 0x97, 0xd7, 0x61, 0x73, 0x1a, 0x1c, 0xf6, 0xf5, 0xb7, 0x8b, 0x99, 0x85, 0x14, 0x4b, 0x86, 0xc1, 0x6, 0x56, 0xb, 0xc5, 0xdb, 0xd1, 0xc, 0xeb, 0x6d, 0x41, 0xf9, 0x80, 0x7f, 0x9b, 0x31, 0xc8, 0xc2, 0x9b, 0x5c, 0x2c, 0x56, 0x75, 0x75, 0x64, 0xd3, 0x99, 0x55, 0xfb, 0x53, 0xd6, 0x17, 0x7f, 0xde, 0x1b, 0x76, 0x4c, 0x89, 0x52, 0xe3, 0xb9, 0xcd, 0xd4, 0xf3, 0x33, 0x4, 0x22, 0xfb, 0x8f, 0xe1, 0xad, 0x69, 0x59, 0x17, 0x5b, 0x29, 0xce, 0xb8, 0xa4, 0xa0, 0xd4, 0xcc, 0xc, 0x60, 0xe1, 0xf, 0xfd, 0x25, 0x3f, 0x42, 0xb2, 0xbf, 0xb0, 0x89, 0xa6, 0x19, 0xd1, 0x5f, 0xbc, 0x21, 0xf9, 0x70, 0x3b, 0xea, 0xf, 0x99, 0xa3, 0x1b, 0x32, 0x27, 0x38, 0xdc, 0x4e, 0xd9, 0x7f, 0x33, 0xf6, 0xdf, 0xbc, 0xcf, 0x92, 0xa5, 0x67, 0x64, 0x69, 0x2c, 0x69, 0x3b, 0xa7, 0xd, 0x8e, 0x1a, 0xd8, 0x4d, 0xb2, 0xcc, 0x53, 0xd9, 0xd1, 0xc2, 0x99, 0xbb, 0xf0, 0xb2, 0x7a, 0xc3, 0x66, 0xc7, 0xb4, 0xa5, 0xcf, 0x3f, 0xf5, 0xd7, 0xd8, 0x26, 0x8e, 0x4d, 0xe2, 0xc4, 0x26, 0x4e, 0x4c, 0xe2, 0xd4, 0x26, 0x4e, 0x4d, 0xe2, 0xcc, 0x26, 0xce, 0x4c, 0xe2, 0xdc, 0x26, 0xce, 0x55, 0xa2, 0x2d, 0xdc, 0x94, 0x6d, 0x8b, 0x36, 0x25, 0xdb, 0x82, 0x4d, 0xb9, 0xb6, 0x58, 0x53, 0xaa, 0x2d, 0xd4, 0x94, 0x69, 0x8b, 0xd4, 0x25, 0x3a, 0xc3, 0xde, 0xa9, 0x2f, 0x1d, 0xd7, 0x9, 0x38, 0xed, 0xa0, 0x65, 0x9f, 0x50, 0xf9, 0x51, 0x36, 0x64, 0xb6, 0xf2, 0xb5, 0x52, 0xbd, 0x57, 0x2c, 0xc0, 0xc7, 0xce, 0x67, 0x3f, 0x5e, 0x1d, 0xdd, 0xd1, 0x2a, 0x3, 0xf8, 0x97, 0xcc, 0x52, 0x35, 0x78, 0x5d, 0xc3, 0xbe, 0xaa, 0x7d, 0xf4, 0xa, 0x85, 0x68, 0x81, 0xed, 0x8, 0x24, 0x4e, 0x9e, 0x4, 0x6f, 0xac, 0x25, 0xc6, 0x30, 0x75, 0x2c, 0x52, 0x27, 0xbc, 0x7d, 0x6c, 0xea, 0x78, 0x2e, 0xeb, 0xc1, 0x58, 0x80, 0x83, 0xf, 0x49, 0x81, 0xc9, 0x62, 0x76, 0x71, 0x47, 0x6, 0x57, 0x21, 0xa7, 0x39, 0x4c, 0x9d, 0xb0, 0xd4, 0xa3, 0x71, 0x6f, 0xbd, 0xac, 0xa7, 0xa5, 0x53, 0xf3, 0xd1, 0x2f, 0x62, 0xed, 0x40, 0xde, 0x47, 0xfd, 0x93, 0xec, 0x8b, 0xd3, 0xab, 0x9a, 0xdf, 0xfc, 0xb4, 0x63, 0x64, 0xa4, 0x35, 0x79, 0x9c, 0x7f, 0x3c, 0x7e, 0x7d, 0x7f, 0x91, 0x5, 0x80, 0xba, 0x8c, 0x45, 0xb9, 0x57, 0x25, 0x2e, 0x5f, 0x56, 0x1f, 0xe7, 0x4c, 0x56, 0x7c, 0x11, 0xa8, 0xef, 0xad, 0x4, 0x99, 0x61, 0x63, 0x56, 0xac, 0xa7, 0xa5, 0x31, 0x95, 0xc3, 0x71, 0xb9, 0x63, 0x83, 0x47, 0x3e, 0x62, 0xa8, 0xcb, 0x8d, 0x5a, 0x85, 0x90, 0xfe, 0x9a, 0xff, 0x56, 0xa0, 0x13, 0xe7, 0x13, 0xc2, 0x44, 0x82, 0x2, 0xae, 0x4a, 0x6e, 0xab, 0x20, 0x54, 0xa6, 0x28, 0x30, 0x5f, 0x21, 0xac, 0x36, 0xdf, 0x20, 0x5c, 0x25, 0x29, 0x84, 0xfd, 0xe1, 0xcb, 0xa9, 0x38, 0x5e, 0xbe, 0x6c, 0x99, 0xb3, 0x17, 0xd3, 0x4a, 0x3e, 0x6f, 0xe5, 0x49, 0x9a, 0xaf, 0xc3, 0x97, 0xf2, 0xb4, 0x62, 0xce, 0xcb, 0x5f, 0x22, 0x31, 0x0, 0x85, 0x78, 0x66, 0x13, 0x5f, 0x14, 0xd1, 0x0, 0x34, 0xc7, 0xc5, 0x51, 0x2c, 0xa0, 0xfd, 0x16, 0x60, 0x5a, 0x88, 0x42, 0xdd, 0x9d, 0xf9, 0x74, 0x4e, 0xc9, 0x6e, 0x5a, 0xce, 0xd6, 0xf3, 0xd5, 0xb5, 0x90, 0x20, 0x36, 0x17, 0xe5, 0xeb, 0x91, 0xee, 0x10, 0x6c, 0x39, 0x9a, 0x4d, 0x46, 0x33, 0x8d, 0xd2, 0x9c, 0x57, 0xab, 0xb2, 0x69, 0xbc, 0x51, 0xda, 0x98, 0xff, 0xd1, 0x28, 0xd5, 0x7e, 0x73, 0x88, 0xc1, 0xbf, 0x14, 0xa7, 0x3d, 0x6f, 0xa8, 0x8, 0xca, 0xba, 0xd8, 0xbf, 0x30, 0x4f, 0x86, 0x61, 0xc, 0x97, 0x2f, 0x9a, 0xcf, 0x8b, 0x9d, 0x37, 0x20, 0xa3, 0x14, 0x39, 0x74, 0x64, 0x14, 0x6d, 0x6, 0x45, 0x30, 0xc4, 0x55, 0x75, 0xe4, 0xa8, 0xaa, 0x82, 0x8, 0xd2, 0x6c, 0xb5, 0xfc, 0x38, 0x5b, 0x49, 0x82, 0xae, 0x18, 0x42, 0xdc, 0xe9, 0xf4, 0x69, 0x3d, 0x9d, 0xa, 0x82, 0x5c, 0x1c, 0x18, 0xb5, 0xe5, 0x2a, 0x5b, 0x97, 0x92, 0x1a, 0x90, 0x58, 0x88, 0x38, 0x19, 0x2d, 0xb3, 0xb5, 0xe4, 0x4d, 0x49, 0x8e, 0xec, 0x3, 0x92, 0x9a, 0x2b, 0xdf, 0x10, 0xb7, 0x5c, 0x3d, 0x3d, 0x8e, 0x36, 0x82, 0xa0, 0x94, 0x33, 0x82, 0xb3, 0x7e, 0x9a, 0x4d, 0xa6, 0x1b, 0x49, 0xcf, 0x69, 0x8c, 0x10, 0x75, 0xf5, 0x34, 0xc9, 0xc6, 0xab, 0xeb, 0x50, 0xcc, 0x5b, 0xe5, 0x34, 0x59, 0xf, 0x2b, 0xb5, 0xf9, 0x78, 0x2, 0xb6, 0x38, 0x9f, 0x32, 0x83, 0xc6, 0xac, 0xd, 0x18, 0x40, 0x19, 0xf3, 0x6c, 0x87, 0x4e, 0xca, 0x4b, 0x1d, 0xea, 0xfe, 0xb9, 0x86, 0x66, 0x3d, 0xc3, 0x2d, 0xfa, 0xa1, 0xee, 0x31, 0x54, 0xf6, 0xf7, 0x99, 0x67, 0xe8, 0x89, 0x6c, 0x3d, 0x9b, 0x53, 0x21, 0xb3, 0x81, 0x51, 0x5d, 0x35, 0xac, 0x57, 0xed, 0xc5, 0x92, 0xf3, 0xda, 0xb0, 0xc9, 0xed, 0x42, 0xce, 0x2d, 0x58, 0xa3, 0x57, 0xa3, 0xe5, 0xe4, 0x59, 0x24, 0xc8, 0x1, 0x65, 0x2, 0x57, 0xb3, 0x25, 0xa0, 0x3, 0x69, 0x46, 0x6d, 0xe6, 0xe7, 0xba, 0xc2, 0x57, 0xee, 0x1d, 0xa2, 0x33, 0x3b, 0xde, 0x93, 0xe6, 0x89, 0xa7, 0x5c, 0xd7, 0xd1, 0xfa, 0x73, 0x29, 0x5e, 0xd7, 0xeb, 0xfe, 0xba, 0xbd, 0xe0, 0xc3, 0xf7, 0x2b, 0x83, 0x4, 0x2b, 0xef, 0xc6, 0xbc, 0xcb, 0xca, 0x44, 0x4c, 0xf5, 0xba, 0x1e, 0x6c, 0xf, 0xa7, 0xea, 0x37, 0x46, 0xa1, 0xa8, 0x7b, 0x9c, 0x56, 0x7d, 0x28, 0x5a, 0x61, 0x48, 0xf5, 0xe0, 0x75, 0xce, 0x67, 0xbc, 0x6c, 0x14, 0x5d, 0x9c, 0x64, 0xb2, 0x6f, 0x53, 0x83, 0x91, 0xab, 0x40, 0x30, 0x89, 0x65, 0xcd, 0x6, 0x8e, 0x4d, 0xd5, 0x2c, 0x30, 0x6b, 0xe9, 0x15, 0xef, 0xf2, 0x3d, 0xfa, 0x98, 0x71, 0xb7, 0x21, 0x16, 0x95, 0xd6, 0x45, 0x5b, 0xc, 0x18, 0x26, 0x3, 0xb2, 0xd9, 0x99, 0x5c, 0x62, 0xea, 0x83, 0xe5, 0x26, 0x3d, 0xc, 0xdd, 0x96, 0xf5, 0x11, 0xd1, 0x3a, 0x35, 0x6b, 0xd4, 0xe6, 0x70, 0x58, 0xed, 0xd9, 0x60, 0x98, 0xd5, 0xa1, 0xd9, 0x1, 0x47, 0xf4, 0xc4, 0x66, 0x10, 0xa4, 0x19, 0xb6, 0xb, 0x4e, 0x66, 0x4e, 0x25, 0x75, 0xb3, 0x7, 0x46, 0x52, 0xc2, 0xcd, 0xfa, 0xbe, 0xf4, 0xe3, 0xf0, 0x71, 0x66, 0xbb, 0x82, 0xd6, 0x4, 0xdd, 0x11, 0x14, 0x47, 0x96, 0x3c, 0x53, 0xee, 0xbc, 0x2e, 0x98, 0x6a, 0xad, 0xb6, 0x55, 0xbd, 0xee, 0x3, 0xc0, 0x91, 0x48, 0x3f, 0xc3, 0xc, 0x41, 0x97, 0x0, 0x88, 0xca, 0x1, 0x83, 0x14, 0xb5, 0x97, 0x5, 0x52, 0xa4, 0x77, 0x76, 0xe7, 0xa2, 0xc0, 0x57, 0x67, 0x3f, 0x76, 0x5a, 0x83, 0x8, 0x4b, 0x55, 0xab, 0x33, 0x61, 0xe1, 0x8, 0x0, 0x66, 0x30, 0x8b, 0x7e, 0x7f, 0xfc, 0xdb, 0x38, 0x1b, 0x4d, 0x7b, 0x7f, 0xcb, 0xb2, 0x7f, 0xcb, 0xfe, 0xc8, 0x8c, 0x9b, 0x41, 0x67, 0x73, 0x6c, 0xa6, 0x6b, 0xd, 0xa4, 0x30, 0x3c, 0x9e, 0xeb, 0x5a, 0xd, 0x1, 0xdc, 0x1e, 0x37, 0x82, 0x9d, 0x50, 0x75, 0x75, 0x3d, 0x3b, 0xd4, 0x5d, 0xd2, 0x6d, 0x1a, 0xa7, 0xe1, 0xb2, 0x45, 0x38, 0xa2, 0x8, 0x39, 0xf1, 0xaa, 0x8c, 0x61, 0xb8, 0x75, 0xc7, 0x30, 0x8, 0xa9, 0x81, 0xaa, 0x91, 0x92, 0x85, 0x38, 0x94, 0x90, 0x21, 0xe, 0x2e, 0xef, 0x3f, 0xc6, 0xaa, 0x26, 0x97, 0xdc, 0x22, 0x35, 0xa3, 0x11, 0x20, 0x81, 0x68, 0xbd, 0x62, 0x28, 0x4e, 0x29, 0xb1, 0x5a, 0xb9, 0x2b, 0xc7, 0x7f, 0x14, 0xea, 0xd3, 0x13, 0xaa, 0xf4, 0xc7, 0x2b, 0x53, 0x3, 0xbe, 0xf5, 0x4a, 0x8f, 0x85, 0x95, 0xf9, 0x3f, 0x31, 0x4a, 0x84, 0xda, 0x53, 0x7b, 0x72, 0x6a, 0x5e, 0xfb, 0x97, 0x72, 0x5f, 0x1f, 0xfa, 0x7f, 0x39, 0xec, 0x8b, 0xd5, 0xa1, 0xff, 0xef, 0x87, 0x3d, 0xd3, 0xac, 0xa2, 0xe9, 0xbf, 0xfb, 0xf7, 0xc3, 0xf9, 0x54, 0x95, 0xa7, 0xde, 0x5f, 0xcb, 0x2f, 0xef, 0xfa, 0xbb, 0xc3, 0xfe, 0x20, 0xac, 0xa2, 0xa0, 0x65, 0xac, 0xb, 0xf7, 0xa2, 0x53, 0xc7, 0x92, 0x70, 0xfb, 0xa4, 0x7d, 0xf2, 0xe3, 0x78, 0xc6, 0x86, 0xc4, 0xc8, 0x38, 0xe1, 0x69, 0x33, 0xde, 0x4c, 0xfd, 0x45, 0x9a, 0x2b, 0x63, 0xb0, 0x1b, 0x61, 0x7c, 0xa8, 0x35, 0x99, 0x4c, 0xc8, 0x75, 0x1f, 0xb0, 0xf1, 0x50, 0xed, 0x9b, 0xb2, 0x65, 0x16, 0x90, 0xaf, 0x6c, 0xb0, 0x7f, 0x4e, 0x2f, 0xcb, 0x42, 0x2d, 0x5e, 0xc, 0xc7, 0xb3, 0xf7, 0x8b, 0xce, 0x98, 0x9c, 0xdd, 0x1e, 0x64, 0x39, 0x83, 0xf6, 0x94, 0x2f, 0xf4, 0x78, 0x1e, 0x8f, 0xda, 0x1f, 0xf1, 0x77, 0x45, 0xc4, 0x9e, 0xaa, 0x6b, 0xdb, 0xac, 0x31, 0x77, 0xad, 0xb8, 0x9a, 0x5f, 0x82, 0x72, 0x23, 0x4b, 0x68, 0x5f, 0x98, 0x6c, 0xe4, 0x92, 0x7e, 0xae, 0x16, 0xf6, 0xeb, 0x5a, 0x26, 0x72, 0x37, 0xa7, 0xd2, 0xf8, 0xef, 0x5, 0x14, 0x68, 0xd8, 0x78, 0x33, 0xfe, 0x7, 0x59, 0x77, 0x5b, 0xad, 0x56, 0x41, 0x93, 0xb2, 0xaa, 0xf4, 0x1c, 0x85, 0xc9, 0x90, 0xe5, 0x5a, 0x77, 0xaf, 0x17, 0x7a, 0x60, 0x96, 0x5d, 0x30, 0xb7, 0x88, 0xed, 0xfb, 0x7, 0x85, 0xe, 0x79, 0xb6, 0x66, 0x75, 0xe2, 0x3b, 0x0, 0x7c, 0x6b, 0x80, 0xaf, 0xbf, 0x29, 0x71, 0x4c, 0xa6, 0x5c, 0x82, 0xda, 0xed, 0xf, 0xbe, 0xe5, 0x12, 0xed, 0x3a, 0xe4, 0x7d, 0xaf, 0xa8, 0xf8, 0x6, 0xab, 0xfd, 0x1c, 0x6c, 0xea, 0x73, 0x65, 0x7c, 0xd5, 0xc9, 0x5f, 0x7f, 0x92, 0xc6, 0x56, 0x24, 0x38, 0xb6, 0x7a, 0x14, 0xe, 0xa1, 0xc4, 0xe4, 0x97, 0x1e, 0xdf, 0x98, 0x12, 0x2f, 0x2a, 0x7d, 0x26, 0xc6, 0x14, 0x61, 0x86, 0xa7, 0xa7, 0x31, 0x9a, 0xe1, 0xe9, 0x91, 0xc8, 0x30, 0x1a, 0x67, 0x19, 0x9a, 0x63, 0x34, 0x92, 0x59, 0x86, 0xa7, 0xc3, 0x17, 0x67, 0x3c, 0x33, 0x18, 0x81, 0x15, 0xb, 0xc9, 0xfd, 0x40, 0xce, 0xdd, 0x99, 0xe0, 0x7, 0xf5, 0xcb, 0x60, 0xd4, 0x37, 0x5f, 0x99, 0xfd, 0x4, 0xa9, 0x63, 0xf3, 0x69, 0xbf, 0x26, 0xe6, 0x6b, 0x6a, 0xbe, 0x66, 0xe6, 0x6b, 0x6e, 0xbe, 0x1e, 0xcd, 0xd7, 0x47, 0xf3, 0xf5, 0x24, 0xbf, 0x76, 0x6b, 0x5d, 0x34, 0xff, 0xca, 0xec, 0x27, 0x48, 0x1d, 0x9b, 0x4f, 0xfb, 0x35, 0x31, 0x5f, 0x53, 0xf3, 0x35, 0x33, 0x5f, 0x73, 0xf3, 0xf5, 0x68, 0xbe, 0x3e, 0x9a, 0x2f, 0x55, 0x74, 0xb3, 0xd3, 0x45, 0xf3, 0xaf, 0xcc, 0x7e, 0x82, 0xd4, 0xb1, 0xf9, 0xb4, 0x5f, 0x13, 0xf3, 0x35, 0x35, 0x5f, 0x33, 0xf3, 0x35, 0x37, 0x5f, 0x8f, 0xe6, 0xeb, 0xa3, 0xf9, 0x52, 0x45, 0x7f, 0x6d, 0x74, 0xd1, 0xfc, 0x2b, 0xb3, 0x9f, 0x20, 0x75, 0x6c, 0x3e, 0xed, 0xd7, 0xc4, 0x7c, 0x4d, 0xcd, 0xd7, 0xcc, 0x7c, 0xcd, 0xcd, 0xd7, 0xa3, 0xf9, 0xfa, 0x68, 0xbe, 0x9e, 0x2e, 0xe1, 0x49, 0x15, 0xae, 0x52, 0x60, 0x75, 0xb8, 0x93, 0xc2, 0xff, 0x13, 0x2b, 0x60, 0x27, 0x8, 0x96, 0x8b, 0xf1, 0xc5, 0x2e, 0xc2, 0xdb, 0xd4, 0x91, 0xee, 0x42, 0xa3, 0xe1, 0x5c, 0xfe, 0xef, 0x11, 0x40, 0x33, 0x5, 0xfd, 0x38, 0x19, 0x4e, 0xd4, 0xff, 0x2c, 0xf4, 0xc9, 0x74, 0x57, 0x9b, 0xf6, 0x51, 0xa5, 0xcd, 0xe7, 0x8, 0xb9, 0x47, 0x5, 0x9c, 0x7d, 0x44, 0xa8, 0xcd, 0x35, 0x10, 0x70, 0x37, 0x53, 0x69, 0x53, 0x8c, 0xb9, 0xa9, 0x2, 0x4e, 0x30, 0xde, 0x26, 0xa, 0x38, 0x6, 0xbc, 0x19, 0x1, 0x60, 0xbc, 0x69, 0x39, 0x60, 0xac, 0x89, 0xf1, 0xa, 0x93, 0x9f, 0x6a, 0x5b, 0x28, 0x3f, 0x9, 0x1a, 0x29, 0x10, 0x2a, 0x44, 0x89, 0x92, 0x29, 0x14, 0x54, 0x92, 0x2, 0xe5, 0x49, 0x61, 0x40, 0x71, 0xa, 0xc0, 0x47, 0x5, 0x40, 0x65, 0x2a, 0x30, 0x1e, 0x15, 0xc6, 0x8c, 0xe4, 0x7e, 0xae, 0x31, 0x7c, 0xde, 0x67, 0xa, 0x30, 0x25, 0x59, 0x9f, 0x2a, 0x8c, 0x9, 0xc9, 0xf9, 0x44, 0x61, 0x8c, 0x7d, 0xce, 0x8d, 0xc8, 0x48, 0xce, 0xb5, 0xe4, 0x48, 0xc6, 0xb5, 0xdc, 0xe4, 0x76, 0x91, 0x81, 0x34, 0x5b, 0xde, 0x20, 0xb2, 0xfb, 0xb9, 0xed, 0xc1, 0x21, 0x23, 0x9, 0x21, 0x9a, 0x83, 0x63, 0x64, 0x12, 0x83, 0x68, 0xd, 0x86, 0xf1, 0x24, 0x11, 0xdc, 0xc6, 0x60, 0xe9, 0x1f, 0x65, 0x3a, 0xd1, 0x16, 0xc, 0xe1, 0x51, 0x22, 0x10, 0x4d, 0xc1, 0x10, 0xe6, 0xa, 0xc1, 0xe7, 0x7a, 0x26, 0xd3, 0xa7, 0x24, 0xd3, 0x53, 0x89, 0x30, 0x21, 0x79, 0x9e, 0x48, 0x84, 0xb1, 0xcf, 0xb3, 0x16, 0x14, 0xc9, 0xb3, 0x92, 0x17, 0xc9, 0xb2, 0x92, 0x96, 0xd3, 0x6, 0x72, 0x97, 0x96, 0xb7, 0x82, 0xb3, 0x1c, 0x0, 0x1b, 0x43, 0xa3, 0x8c, 0x1c, 0x14, 0xb4, 0x55, 0x34, 0x6a, 0xe6, 0xa0, 0xa2, 0xcd, 0xa3, 0x50, 0x9f, 0x1c, 0x4c, 0xd8, 0x4e, 0xa, 0xe1, 0xa3, 0x83, 0x80, 0x36, 0x98, 0xc2, 0x7c, 0x74, 0x30, 0xd1, 0x96, 0x53, 0x98, 0x73, 0x17, 0x33, 0xac, 0xeb, 0xcc, 0x41, 0x98, 0x46, 0xaa, 0x3a, 0x75, 0x30, 0x27, 0x91, 0x9a, 0x4e, 0x1c, 0xcc, 0x71, 0x58, 0x53, 0xaf, 0x9, 0x22, 0x35, 0x75, 0x5b, 0x22, 0x52, 0xd1, 0xac, 0xf3, 0xe2, 0xd4, 0x3f, 0x6d, 0x80, 0x10, 0x38, 0x39, 0x51, 0x4a, 0xe0, 0xe4, 0x4, 0x1b, 0xa4, 0x93, 0x13, 0xfc, 0x92, 0x4e, 0x4e, 0x14, 0xe3, 0x39, 0x39, 0xce, 0x4, 0xe9, 0xe4, 0x38, 0xaf, 0xa4, 0x93, 0xe3, 0x55, 0xf2, 0x9d, 0x1c, 0xaf, 0x30, 0xe9, 0xe4, 0xb8, 0x5c, 0x48, 0x27, 0xc7, 0xc5, 0xe7, 0x3b, 0x39, 0x2e, 0x5c, 0xd2, 0xc9, 0xf1, 0xaa, 0x52, 0x4e, 0x8e, 0xc1, 0x28, 0x27, 0x67, 0x40, 0xb4, 0x93, 0x33, 0x28, 0xb4, 0x93, 0xd3, 0x28, 0x81, 0x93, 0xd3, 0x0, 0xda, 0xc9, 0x69, 0xc, 0xda, 0xc9, 0x69, 0x8c, 0xc0, 0xc9, 0x69, 0x0, 0xed, 0xe4, 0x34, 0x6, 0xed, 0xe4, 0x34, 0x46, 0xe0, 0xe4, 0x34, 0x80, 0x76, 0x72, 0x46, 0x2e, 0x94, 0x93, 0xd3, 0x8, 0xa1, 0x93, 0x13, 0x10, 0xd4, 0xc9, 0x19, 0x8, 0xe9, 0xe4, 0xc, 0x6, 0xe9, 0xe4, 0x34, 0x86, 0xef, 0xe4, 0x74, 0x3a, 0xe9, 0xe4, 0x34, 0x2, 0xe9, 0xe4, 0x34, 0x82, 0xef, 0xe4, 0x74, 0x3a, 0xe9, 0xe4, 0x34, 0x2, 0xe9, 0xe4, 0x34, 0x82, 0xef, 0xe4, 0x74, 0x3a, 0xe9, 0xe4, 0x8c, 0x38, 0x8, 0x27, 0xa7, 0xe1, 0x81, 0x93, 0x63, 0x80, 0x94, 0x93, 0x3, 0x28, 0x29, 0x27, 0x7, 0x50, 0x53, 0x4e, 0xce, 0xa2, 0x12, 0x4e, 0xce, 0x22, 0xa4, 0x9c, 0x9c, 0xc5, 0x4c, 0x39, 0x39, 0x8b, 0x49, 0x38, 0x39, 0x8b, 0x90, 0x72, 0x72, 0x16, 0x33, 0xe5, 0xe4, 0x2c, 0x26, 0xe1, 0xe4, 0x2c, 0x42, 0xca, 0xc9, 0x1, 0xf9, 0xc6, 0x9d, 0x9c, 0x45, 0xf4, 0x9d, 0x5c, 0x74, 0xc5, 0xe1, 0x9f, 0x34, 0x3, 0xf, 0xbc, 0x9c, 0x28, 0x25, 0xf0, 0x72, 0x82, 0xd, 0xd2, 0xcb, 0x9, 0x7e, 0x49, 0x2f, 0x27, 0x8a, 0xf1, 0xbc, 0x1c, 0x67, 0x82, 0xf4, 0x72, 0x9c, 0x57, 0xd2, 0xcb, 0xf1, 0x2a, 0xf9, 0x5e, 0x8e, 0x57, 0x98, 0xf4, 0x72, 0x5c, 0x2e, 0xa4, 0x97, 0xe3, 0xe2, 0xf3, 0xbd, 0x1c, 0x17, 0x2e, 0xe9, 0xe5, 0x78, 0x55, 0x29, 0x2f, 0xc7, 0x60, 0x94, 0x97, 0x33, 0x20, 0xda, 0xcb, 0x19, 0x14, 0xda, 0xcb, 0x69, 0x94, 0xc0, 0xcb, 0x69, 0x0, 0xed, 0xe5, 0x34, 0x6, 0xed, 0xe5, 0x34, 0x46, 0xe0, 0xe5, 0x34, 0x80, 0xf6, 0x72, 0x1a, 0x83, 0xf6, 0x72, 0x1a, 0x23, 0xf0, 0x72, 0x1a, 0x40, 0x7b, 0x39, 0x23, 0x17, 0xca, 0xcb, 0x69, 0x84, 0xd0, 0xcb, 0x9, 0x8, 0xea, 0xe5, 0xc, 0x84, 0xf4, 0x72, 0x6, 0x83, 0xf4, 0x72, 0x1a, 0xc3, 0xf7, 0x72, 0x3a, 0x9d, 0xf4, 0x72, 0x1a, 0x81, 0xf4, 0x72, 0x1a, 0xc1, 0xf7, 0x72, 0x3a, 0x9d, 0xf4, 0x72, 0x1a, 0x81, 0xf4, 0x72, 0x1a, 0xc1, 0xf7, 0x72, 0x3a, 0x9d, 0xf4, 0x72, 0x46, 0x1c, 0x84, 0x97, 0xd3, 0xf0, 0xc0, 0xcb, 0x31, 0x40, 0xca, 0xcb, 0x1, 0x94, 0x94, 0x97, 0x3, 0xa8, 0x29, 0x2f, 0x67, 0x51, 0x9, 0x2f, 0x67, 0x11, 0x52, 0x5e, 0xce, 0x62, 0xa6, 0xbc, 0x9c, 0xc5, 0x24, 0xbc, 0x9c, 0x45, 0x48, 0x79, 0x39, 0x8b, 0x99, 0xf2, 0x72, 0x16, 0x93, 0xf0, 0x72, 0x16, 0x21, 0xe5, 0xe5, 0x80, 0x7c, 0xe3, 0x5e, 0xce, 0x22, 0x76, 0xf0, 0x72, 0x60, 0x99, 0xfc, 0x9f, 0xb4, 0xc6, 0x1d, 0xb8, 0x39, 0x51, 0x4a, 0xe0, 0xe6, 0x4, 0x1b, 0xa4, 0x9b, 0x13, 0xfc, 0x92, 0x6e, 0x4e, 0x14, 0xe3, 0xb9, 0x39, 0xce, 0x4, 0xe9, 0xe6, 0x38, 0xaf, 0xa4, 0x9b, 0xe3, 0x55, 0xf2, 0xdd, 0x1c, 0xaf, 0x30, 0xe9, 0xe6, 0xb8, 0x5c, 0x48, 0x37, 0xc7, 0xc5, 0xe7, 0xbb, 0x39, 0x2e, 0x5c, 0xd2, 0xcd, 0xf1, 0xaa, 0x52, 0x6e, 0x8e, 0xc1, 0x28, 0x37, 0x67, 0x40, 0xb4, 0x9b, 0x33, 0x28, 0xb4, 0x9b, 0xd3, 0x28, 0x81, 0x9b, 0xd3, 0x0, 0xda, 0xcd, 0x69, 0xc, 0xda, 0xcd, 0x69, 0x8c, 0xc0, 0xcd, 0x69, 0x0, 0xed, 0xe6, 0x34, 0x6, 0xed, 0xe6, 0x34, 0x46, 0xe0, 0xe6, 0x34, 0x80, 0x76, 0x73, 0x46, 0x2e, 0x94, 0x9b, 0xd3, 0x8, 0xa1, 0x9b, 0x13, 0x10, 0xd4, 0xcd, 0x19, 0x8, 0xe9, 0xe6, 0xc, 0x6, 0xe9, 0xe6, 0x34, 0x86, 0xef, 0xe6, 0x74, 0x3a, 0xe9, 0xe6, 0x34, 0x2, 0xe9, 0xe6, 0x34, 0x82, 0xef, 0xe6, 0x74, 0x3a, 0xe9, 0xe6, 0x34, 0x2, 0xe9, 0xe6, 0x34, 0x82, 0xef, 0xe6, 0x74, 0x3a, 0xe9, 0xe6, 0x8c, 0x38, 0x8, 0x37, 0xa7, 0xe1, 0x81, 0x9b, 0x63, 0x80, 0x94, 0x9b, 0x3, 0x28, 0x29, 0x37, 0x7, 0x50, 0x53, 0x6e, 0xce, 0xa2, 0x12, 0x6e, 0xce, 0x22, 0xa4, 0xdc, 0x9c, 0xc5, 0x4c, 0xb9, 0x39, 0x8b, 0x49, 0xb8, 0x39, 0x8b, 0x90, 0x72, 0x73, 0x16, 0x33, 0xe5, 0xe6, 0x2c, 0x26, 0xe1, 0xe6, 0x2c, 0x42, 0xca, 0xcd, 0x1, 0xf9, 0xc6, 0xdd, 0x9c, 0x45, 0xc, 0xdc, 0x9c, 0xba, 0x17, 0x17, 0xbb, 0x31, 0xaf, 0x82, 0x6, 0x98, 0xe3, 0x47, 0xfc, 0x70, 0xdf, 0x1c, 0x6c, 0xe6, 0xa9, 0xc3, 0x26, 0x3c, 0xc9, 0x39, 0xaa, 0xbb, 0xf0, 0x8f, 0x33, 0xb7, 0x5b, 0xe4, 0x84, 0xb3, 0x28, 0x1f, 0x5c, 0x7c, 0xf1, 0xee, 0xc1, 0x20, 0x67, 0x8, 0x65, 0x9e, 0xe7, 0x96, 0x5f, 0x49, 0x7b, 0x6e, 0x4f, 0xcf, 0xe6, 0xb6, 0x1d, 0x48, 0xda, 0x9a, 0x24, 0x7e, 0xbc, 0xc6, 0xc3, 0x32, 0x49, 0x16, 0x8b, 0x1f, 0x6, 0xf5, 0xb0, 0x4c, 0xd2, 0xf6, 0xe2, 0x9c, 0xac, 0x20, 0xe, 0x4e, 0x78, 0xf7, 0xad, 0x98, 0x90, 0x88, 0xab, 0x36, 0xfa, 0xe0, 0x5e, 0x58, 0x8c, 0x7f, 0xd1, 0x5f, 0xd4, 0xd9, 0x3b, 0x2, 0x38, 0xa6, 0x8, 0xa9, 0x56, 0x7a, 0xd0, 0x4, 0xf3, 0x4d, 0x75, 0xd2, 0x27, 0xe9, 0x40, 0xb5, 0xe2, 0x68, 0x46, 0x20, 0xac, 0x21, 0xc5, 0xfd, 0xd1, 0x24, 0xb9, 0x38, 0x9e, 0x2b, 0x60, 0x17, 0x46, 0x91, 0x4c, 0xa3, 0x6e, 0xc1, 0x5d, 0xd0, 0x3c, 0x73, 0xf4, 0xe1, 0x41, 0xfc, 0xd, 0xe1, 0x94, 0xc0, 0x7a, 0x43, 0x42, 0xf5, 0xf5, 0x15, 0x43, 0x75, 0x83, 0x73, 0x75, 0xd8, 0xaf, 0xcb, 0x7d, 0x53, 0xae, 0x11, 0x85, 0x43, 0x81, 0x5b, 0x4, 0x18, 0x28, 0x21, 0xa, 0xc4, 0x72, 0x6, 0x8a, 0x89, 0x2, 0xad, 0x8a, 0x4e, 0x4c, 0x7, 0x31, 0x77, 0x4f, 0xfd, 0xbb, 0xa8, 0x58, 0x45, 0x10, 0xd8, 0x36, 0x84, 0x85, 0xd5, 0x40, 0x60, 0x48, 0xbe, 0xb0, 0x12, 0x8, 0xc, 0xbb, 0x20, 0xeb, 0xb4, 0xd8, 0xbd, 0x4, 0x55, 0xd7, 0x51, 0x56, 0x65, 0x6c, 0x5, 0xd4, 0xb4, 0xa7, 0xea, 0x8, 0xea, 0x9c, 0xef, 0xdb, 0x2d, 0x33, 0x94, 0x3, 0x7e, 0xe7, 0xff, 0xa7, 0xc3, 0x7a, 0xfd, 0x1e, 0x3b, 0x2d, 0xef, 0x70, 0x24, 0xe, 0x9a, 0xdb, 0xfc, 0xe4, 0x11, 0xfb, 0x8f, 0xb3, 0xd9, 0x7c, 0x22, 0x6d, 0x6d, 0x8f, 0xa5, 0xfd, 0xb2, 0xaa, 0x8b, 0xa6, 0xf9, 0xd3, 0xcf, 0xdc, 0x36, 0x7f, 0xa, 0xee, 0xb3, 0xc9, 0x41, 0xbe, 0x38, 0xf4, 0xe5, 0x5e, 0xec, 0x66, 0xe8, 0xe7, 0xdd, 0xfe, 0xaa, 0x2f, 0x28, 0x3b, 0x54, 0xfa, 0xfa, 0xb2, 0xf2, 0xbd, 0xb4, 0x4b, 0x7e, 0xc0, 0xc9, 0x35, 0xa3, 0x43, 0x79, 0x13, 0xf, 0x31, 0xb0, 0x6, 0xb2, 0xd, 0x4d, 0xef, 0x7a, 0xa8, 0x2f, 0xf0, 0x5, 0x46, 0xd9, 0x87, 0x28, 0x9d, 0x41, 0xca, 0xf1, 0x21, 0x98, 0x3d, 0x27, 0xa8, 0x21, 0xe5, 0x28, 0x95, 0x40, 0xca, 0xf1, 0x21, 0x98, 0x47, 0x20, 0xa8, 0xd9, 0x72, 0xe8, 0x16, 0x47, 0xd5, 0x44, 0xe5, 0xca, 0x55, 0xaa, 0x51, 0xe1, 0x28, 0xd6, 0xb6, 0x1f, 0x51, 0xb9, 0x67, 0x97, 0x45, 0xf, 0xc7, 0x56, 0x41, 0x62, 0x53, 0x58, 0x5b, 0x7, 0xb, 0xbb, 0xde, 0xb1, 0x9e, 0x3e, 0xcd, 0xa6, 0x81, 0x96, 0xa8, 0xb, 0x26, 0x98, 0x9a, 0x18, 0x10, 0xaa, 0x27, 0xa, 0x8a, 0x29, 0x8a, 0xf, 0xd2, 0xfa, 0x80, 0x94, 0x15, 0x80, 0x50, 0x5d, 0x21, 0x8, 0x62, 0x65, 0x69, 0x9d, 0x40, 0xca, 0xa, 0x40, 0xa8, 0xbe, 0x10, 0x4, 0x41, 0x59, 0xf4, 0x95, 0x1d, 0x5c, 0x17, 0x9c, 0x3b, 0x3c, 0xb4, 0xca, 0x78, 0x68, 0x9, 0x9d, 0x71, 0xd9, 0x44, 0x94, 0xc6, 0x21, 0x47, 0x6b, 0x4d, 0xf2, 0x82, 0xd1, 0xaa, 0x28, 0xa7, 0xab, 0x40, 0x6d, 0xf8, 0x4d, 0x22, 0x4c, 0x67, 0x64, 0x3a, 0xaa, 0x30, 0x1c, 0x84, 0x69, 0x8b, 0x93, 0xae, 0xf5, 0xc1, 0xa7, 0xef, 0xa6, 0xa3, 0x4a, 0x82, 0xd1, 0x9, 0xe8, 0x6b, 0x1d, 0xf0, 0xe9, 0xbb, 0xe9, 0xa8, 0x62, 0x60, 0x74, 0x34, 0x7d, 0xfa, 0xde, 0x15, 0xde, 0xd6, 0xf6, 0x22, 0x16, 0xad, 0xf, 0x10, 0x27, 0xa1, 0xc, 0x80, 0x35, 0x44, 0x13, 0x2c, 0x21, 0x5a, 0xd, 0xa2, 0x37, 0xc3, 0xa6, 0xf3, 0xe5, 0xc7, 0x75, 0x11, 0xe8, 0x80, 0xba, 0xff, 0x85, 0xa9, 0x81, 0x1, 0xa1, 0x9a, 0xa0, 0xa0, 0x98, 0x32, 0xf8, 0x20, 0xdd, 0xee, 0x48, 0x59, 0x1, 0x8, 0xd5, 0xa, 0x82, 0x20, 0x56, 0x96, 0xd6, 0x1, 0xa4, 0xac, 0x0, 0x84, 0x6a, 0x8, 0x41, 0x10, 0x94, 0x45, 0xdf, 0xa8, 0xc3, 0x75, 0xc0, 0xb9, 0x62, 0x47, 0xab, 0x8a, 0x87, 0x96, 0xd0, 0x16, 0x97, 0x4d, 0x44, 0x61, 0x1c, 0x72, 0xb4, 0xce, 0x24, 0xef, 0xff, 0x95, 0xc5, 0x78, 0x32, 0xf, 0xd4, 0x46, 0x5e, 0xf3, 0xc3, 0xb4, 0x46, 0x43, 0x50, 0xa5, 0x91, 0x40, 0x4c, 0x67, 0x3c, 0x88, 0xd6, 0x8b, 0xb0, 0x1c, 0x1f, 0x82, 0x2a, 0xc, 0x4e, 0xd, 0x29, 0x47, 0xeb, 0x44, 0x58, 0x8e, 0xf, 0x41, 0x95, 0x5, 0xa7, 0x66, 0xcb, 0xa1, 0x2f, 0x4b, 0xe2, 0x3a, 0x0, 0x6f, 0x4f, 0xd2, 0x9a, 0xe2, 0x62, 0x25, 0x14, 0xc5, 0x61, 0x11, 0xd1, 0x13, 0x48, 0x8c, 0x56, 0x93, 0xc4, 0xb5, 0xce, 0xf5, 0x74, 0xb2, 0x99, 0x68, 0xe3, 0x2, 0xe2, 0x94, 0x98, 0x98, 0x5b, 0x83, 0xaf, 0xea, 0x48, 0xbe, 0x3d, 0x9f, 0x3c, 0xcc, 0x46, 0x3f, 0xea, 0x35, 0xfe, 0x66, 0x75, 0x2a, 0xcb, 0x7d, 0xaf, 0xd8, 0xaf, 0x7b, 0x3f, 0xd9, 0xe5, 0x87, 0xc7, 0xf9, 0xa3, 0x58, 0xed, 0xf, 0xa8, 0x92, 0xab, 0x13, 0xa3, 0x99, 0xbc, 0x1f, 0x7, 0x6e, 0xe, 0xa8, 0x7b, 0x84, 0x3c, 0xac, 0xa3, 0x49, 0x95, 0x77, 0x71, 0x78, 0x12, 0x67, 0x8a, 0x61, 0xf0, 0x45, 0x14, 0x79, 0xc5, 0x60, 0x59, 0x9c, 0x16, 0xa9, 0x59, 0x90, 0xe5, 0xe4, 0x59, 0x4d, 0x61, 0x83, 0xab, 0xa3, 0x4, 0x22, 0x36, 0xf1, 0x8b, 0x21, 0x6d, 0x23, 0x48, 0xe1, 0x54, 0x30, 0x86, 0x14, 0xa3, 0x14, 0xce, 0xe5, 0x62, 0x48, 0x5b, 0xfc, 0xaa, 0x3a, 0x9e, 0xcf, 0xcc, 0xa, 0x6d, 0x1c, 0xc4, 0x24, 0x2a, 0x14, 0x12, 0x5c, 0x76, 0xe8, 0xdf, 0x92, 0x73, 0x7b, 0x6b, 0x4e, 0x2b, 0xce, 0xbb, 0x73, 0xde, 0x5c, 0xa6, 0x15, 0xfc, 0xdd, 0x39, 0x9d, 0x32, 0x2f, 0xce, 0xf5, 0xc2, 0x1b, 0x25, 0xd, 0xee, 0x83, 0xde, 0x26, 0xe8, 0xdb, 0x32, 0x2, 0x39, 0xdf, 0x99, 0xf1, 0xd6, 0x12, 0x81, 0x94, 0xef, 0xcc, 0x8, 0x4b, 0xbc, 0x38, 0x37, 0x3c, 0x6f, 0x11, 0x32, 0x20, 0x12, 0xeb, 0x6a, 0x89, 0x8c, 0xdb, 0x1b, 0x64, 0x75, 0x7b, 0x89, 0x58, 0x46, 0x6f, 0x15, 0x87, 0xaf, 0x59, 0x6f, 0xaa, 0xb2, 0x5e, 0x37, 0x65, 0xb, 0xee, 0x8b, 0x99, 0x60, 0x3f, 0x26, 0xce, 0x91, 0xdd, 0xb7, 0xcd, 0xae, 0x75, 0xf9, 0x52, 0xee, 0xd7, 0xde, 0x75, 0x39, 0x60, 0xc6, 0x7d, 0x3a, 0x44, 0x2c, 0x11, 0x19, 0xfd, 0x3, 0xb, 0x1c, 0xe6, 0x87, 0x2d, 0xf3, 0x82, 0x2d, 0x85, 0x41, 0x3, 0x94, 0x49, 0x97, 0x21, 0xeb, 0xba, 0xc4, 0x83, 0x72, 0x19, 0xe3, 0x17, 0x67, 0xc2, 0xf8, 0x94, 0x6f, 0x1d, 0x2f, 0xae, 0x63, 0x68, 0x50, 0x1d, 0x2c, 0x41, 0xdc, 0x7f, 0x74, 0x83, 0xab, 0xc8, 0xb, 0xa7, 0x90, 0xd0, 0xa6, 0xe2, 0x57, 0xdc, 0xdd, 0x28, 0xc2, 0xe, 0x49, 0xe6, 0xe9, 0x3f, 0x91, 0x2d, 0xa5, 0x42, 0xb, 0xfe, 0xb2, 0x3b, 0xd7, 0x6d, 0x75, 0xe4, 0x17, 0xe7, 0x55, 0x2, 0x6f, 0x9f, 0x4f, 0x54, 0xbc, 0x4f, 0x51, 0xa6, 0xa, 0xda, 0x86, 0xd5, 0x29, 0x4, 0xc9, 0x9a, 0x7d, 0xb7, 0x78, 0x6d, 0x2c, 0x8d, 0x15, 0x85, 0x5f, 0xdf, 0x14, 0x8b, 0xd6, 0x4f, 0xee, 0x7d, 0xcd, 0x74, 0xbc, 0x3c, 0xbd, 0x66, 0xcd, 0xaf, 0xfa, 0xf, 0x54, 0x4, 0x65, 0x5a, 0xdf, 0xf5, 0x3d, 0xc7, 0x27, 0x10, 0xb6, 0xeb, 0x23, 0x6b, 0xbe, 0xd1, 0xfc, 0xbe, 0x72, 0x17, 0x68, 0x80, 0x44, 0x98, 0x5a, 0xed, 0x8a, 0x97, 0x52, 0x5f, 0x64, 0xf5, 0xc6, 0x37, 0x91, 0x5b, 0x9a, 0xb1, 0xab, 0xb9, 0x9c, 0x0, 0xff, 0xf, 0xde, 0xb8, 0xcd, 0x1e, 0xf1, 0xcb, 0xb9, 0x24, 0x2e, 0x12, 0xf2, 0xcd, 0xc6, 0x88, 0x64, 0xcd, 0x8, 0xc2, 0xb6, 0xf5, 0x86, 0xa3, 0x59, 0xd3, 0xf, 0x19, 0xa, 0x70, 0xbc, 0x0, 0x71, 0x71, 0x7a, 0x31, 0x3a, 0x6f, 0x41, 0xc4, 0x55, 0x9, 0xa5, 0xd1, 0x90, 0x9a, 0x73, 0x49, 0xd6, 0xc6, 0xc2, 0x76, 0xb3, 0xc9, 0x48, 0xc2, 0x4c, 0x99, 0x56, 0xe5, 0xf6, 0x50, 0xaf, 0x6d, 0xa4, 0x1b, 0x7e, 0x9d, 0xf7, 0xc0, 0x83, 0xd1, 0xb6, 0xdf, 0xf2, 0x91, 0x97, 0x89, 0x8f, 0x70, 0x45, 0x9f, 0x22, 0x32, 0x6, 0x65, 0x98, 0xa8, 0xbf, 0x5d, 0xf3, 0x80, 0x70, 0xc9, 0x6e, 0xfa, 0x89, 0xf9, 0x4e, 0x1e, 0x3b, 0xee, 0x53, 0x5f, 0xfb, 0xa, 0x8b, 0xda, 0x73, 0x3b, 0x9, 0x32, 0xe9, 0x94, 0x46, 0x9c, 0xa8, 0x16, 0x28, 0x33, 0x49, 0x5b, 0x45, 0xf2, 0xd8, 0x1f, 0xf8, 0x9e, 0x27, 0xf, 0x98, 0xb4, 0x36, 0xf1, 0x80, 0x5d, 0xc4, 0x78, 0xa0, 0x62, 0x32, 0xb8, 0x30, 0x32, 0x7f, 0xd1, 0xa8, 0xdc, 0xfd, 0xad, 0xcb, 0xcf, 0xd5, 0xaa, 0x1c, 0x1c, 0xab, 0xaf, 0x65, 0x3d, 0x10, 0xe1, 0x28, 0xf3, 0xec, 0xfd, 0x5, 0xd0, 0x5f, 0x17, 0x6d, 0xe9, 0x58, 0xf4, 0xb6, 0xda, 0xb9, 0x9, 0x1c, 0x83, 0x27, 0xe, 0x98, 0x9, 0x29, 0x6a, 0x7, 0xb4, 0x63, 0xbc, 0x33, 0xde, 0xa0, 0x7d, 0x90, 0x61, 0xc1, 0x64, 0xfb, 0x89, 0x6d, 0xc1, 0x41, 0xb3, 0xeb, 0x5, 0xe5, 0x45, 0x10, 0x64, 0xf9, 0x9, 0xa, 0x90, 0x9f, 0x8, 0xaa, 0xe4, 0xcf, 0xaf, 0xcc, 0x27, 0x95, 0xa3, 0xd9, 0x5, 0xf5, 0x46, 0x21, 0x5e, 0x81, 0x28, 0x8e, 0x2c, 0xc9, 0x80, 0x5c, 0x91, 0x8c, 0x7c, 0x91, 0xd4, 0x2f, 0x9, 0x91, 0xb8, 0x8, 0x88, 0x48, 0x42, 0xa, 0xa4, 0x48, 0x5c, 0xd4, 0xb8, 0x48, 0xea, 0x17, 0x4a, 0x24, 0x2e, 0x4, 0x17, 0x89, 0x8b, 0xe3, 0x88, 0xa4, 0x7e, 0x71, 0x44, 0x32, 0x1b, 0x8b, 0x3b, 0xe5, 0xa2, 0x3, 0xc8, 0x20, 0xd8, 0xfe, 0x34, 0x5a, 0x5c, 0xb, 0x56, 0xde, 0xb9, 0x3f, 0x14, 0xce, 0x18, 0xb9, 0x6d, 0xec, 0x47, 0x19, 0x5, 0x1, 0xf5, 0x90, 0x70, 0x7a, 0x90, 0x66, 0x4f, 0x8c, 0xbb, 0x14, 0x65, 0xf9, 0xe3, 0x2, 0xd6, 0x6, 0xc6, 0xc1, 0xe5, 0xe5, 0x71, 0x48, 0x31, 0xf3, 0x23, 0xb8, 0x5b, 0xea, 0xe8, 0xb8, 0xc9, 0x80, 0x55, 0xa0, 0x25, 0x2, 0x4b, 0xb2, 0x14, 0xc, 0x45, 0x14, 0x0, 0xc9, 0xab, 0x6, 0x61, 0x61, 0xc0, 0x4e, 0xe7, 0xbe, 0xfe, 0xd8, 0xa9, 0xff, 0x83, 0x2f, 0xdd, 0x7, 0x25, 0x64, 0x20, 0xc4, 0x81, 0xd3, 0xa, 0xaa, 0x60, 0x97, 0x8d, 0x48, 0x9b, 0xd0, 0xa1, 0xa3, 0x50, 0x51, 0xa2, 0xc1, 0x6a, 0x17, 0x7e, 0x90, 0x48, 0x4a, 0xe0, 0x8a, 0x9d, 0x87, 0x38, 0xb7, 0xf, 0x2e, 0xef, 0x58, 0xa4, 0x2a, 0x75, 0xd4, 0x9, 0xa9, 0xf8, 0x50, 0x9b, 0x78, 0xdb, 0x8e, 0x26, 0xc9, 0xd1, 0xa6, 0x10, 0x5f, 0x24, 0xfb, 0xc8, 0x98, 0xeb, 0xf0, 0xb4, 0x33, 0x86, 0xa2, 0x2b, 0x88, 0xe1, 0x0, 0xa5, 0xa6, 0xe1, 0x11, 0x2, 0xa8, 0x5e, 0xc6, 0xf1, 0x94, 0x8e, 0x62, 0x39, 0xad, 0x20, 0x30, 0x28, 0x70, 0xa6, 0x1, 0x39, 0x34, 0xa7, 0x4, 0x85, 0x2f, 0x22, 0x40, 0x17, 0xeb, 0xb8, 0xd6, 0x81, 0xdc, 0xf8, 0xbe, 0xf8, 0xa3, 0x6b, 0x3f, 0xec, 0x1b, 0xa2, 0x94, 0xc0, 0x22, 0x4c, 0x44, 0xc, 0x4b, 0x84, 0xae, 0x35, 0x7e, 0x11, 0x28, 0x73, 0x9, 0x5e, 0x9c, 0x26, 0x37, 0xe, 0x42, 0x76, 0xb5, 0x88, 0xc0, 0x6d, 0x98, 0xa1, 0x39, 0xf, 0xe4, 0x24, 0x6c, 0x9a, 0x1b, 0x12, 0xd3, 0x1b, 0x9a, 0xcf, 0x82, 0x10, 0x27, 0x72, 0x6e, 0x84, 0xd3, 0xe, 0x7c, 0x94, 0x3f, 0xb3, 0xb2, 0x9e, 0xce, 0xc, 0x59, 0x7c, 0x42, 0xf2, 0xdc, 0xa0, 0xb5, 0xe3, 0xdc, 0x1, 0xa3, 0xe3, 0x9a, 0xb7, 0xac, 0x4d, 0xd7, 0xe2, 0xd2, 0x15, 0x8c, 0x50, 0xea, 0xbb, 0xc3, 0xb4, 0x78, 0x71, 0x49, 0x31, 0x68, 0x1d, 0x7c, 0x8d, 0x34, 0xa0, 0x32, 0x4e, 0xed, 0x90, 0x82, 0xb9, 0x56, 0xe0, 0x55, 0x6d, 0x8, 0x20, 0x7e, 0xea, 0x69, 0xec, 0x86, 0x46, 0xe2, 0x11, 0x57, 0x3d, 0xb2, 0xea, 0x94, 0x60, 0x5c, 0x71, 0xbc, 0x22, 0x2, 0x4f, 0x4e, 0x28, 0xe, 0xeb, 0x12, 0x9e, 0xe2, 0x58, 0x42, 0x81, 0xc4, 0xd8, 0x30, 0x5, 0x15, 0xed, 0x77, 0xa8, 0x54, 0xd7, 0x52, 0xd3, 0xf5, 0x8c, 0x50, 0x42, 0xf5, 0x87, 0x2a, 0x2e, 0x29, 0xd, 0x4f, 0x7f, 0x5e, 0x23, 0x14, 0xa0, 0x46, 0x53, 0xe1, 0xe7, 0xb6, 0x45, 0x33, 0xd8, 0x94, 0xe5, 0x9a, 0x4f, 0x83, 0x42, 0x7f, 0xee, 0xc2, 0x3d, 0xf6, 0x5d, 0x23, 0x36, 0x95, 0xc1, 0x1, 0x3d, 0x2b, 0x19, 0x92, 0x36, 0xe3, 0x13, 0xe9, 0x79, 0x95, 0x5, 0x5c, 0xfc, 0xc6, 0x3c, 0xd2, 0xba, 0xfc, 0x9a, 0x8f, 0x17, 0xd8, 0xaa, 0x85, 0x58, 0xa9, 0x80, 0xab, 0x16, 0xfe, 0xac, 0x63, 0x11, 0x4, 0xc0, 0x5d, 0xa8, 0x61, 0xc2, 0xa0, 0xfc, 0xcc, 0x7e, 0x37, 0x2a, 0x4c, 0xa6, 0xd6, 0xc4, 0x7, 0x82, 0x4d, 0x75, 0x57, 0x61, 0x6c, 0x8b, 0xc3, 0x95, 0xc1, 0xd8, 0xc2, 0x38, 0xa1, 0x9, 0x88, 0x97, 0x8e, 0x5b, 0x25, 0x21, 0x60, 0x75, 0x82, 0xa2, 0x7, 0x86, 0x65, 0x68, 0xb2, 0x19, 0xd7, 0xb8, 0x50, 0x55, 0xb6, 0x1a, 0x86, 0x38, 0x30, 0x1e, 0x44, 0x52, 0x8e, 0xc2, 0x3c, 0x80, 0x70, 0xa4, 0x58, 0x1a, 0x56, 0x46, 0x30, 0x70, 0xc6, 0x60, 0x7a, 0x6c, 0x8a, 0xa0, 0xc0, 0x21, 0x49, 0x8, 0x70, 0x32, 0x5e, 0xfc, 0xd8, 0xdf, 0x90, 0x41, 0x77, 0xe2, 0xe, 0x17, 0x31, 0xf4, 0xa4, 0xfd, 0x3b, 0xaf, 0x17, 0x45, 0xf8, 0xc1, 0x96, 0x56, 0x4c, 0x20, 0x60, 0x27, 0x17, 0x9c, 0x9f, 0xb1, 0x2e, 0x74, 0xd8, 0x5f, 0x52, 0x8f, 0x5e, 0xe8, 0xb3, 0x41, 0x64, 0xe1, 0x46, 0xef, 0xa4, 0x78, 0xd5, 0xb6, 0xba, 0xaf, 0x4f, 0x41, 0xb2, 0xd3, 0xd6, 0x16, 0x1a, 0xea, 0x93, 0x81, 0xf9, 0xfa, 0x64, 0x0, 0x40, 0x9f, 0xdc, 0x34, 0xac, 0xc, 0x54, 0x9f, 0x7c, 0x18, 0xa2, 0x4f, 0x1a, 0x25, 0xd0, 0x27, 0x7, 0x90, 0xd4, 0x27, 0xc3, 0xe0, 0xbf, 0x88, 0x3e, 0xa1, 0xfc, 0x24, 0xf5, 0xc9, 0xe4, 0xba, 0x5d, 0x9f, 0xf4, 0x81, 0x11, 0x4e, 0xa6, 0x3c, 0x9d, 0xe, 0x27, 0x5f, 0x53, 0xbc, 0x44, 0xa7, 0xd, 0x35, 0x2c, 0xd4, 0x12, 0x5, 0xf1, 0x75, 0x44, 0x25, 0x3, 0xd, 0x81, 0x29, 0x21, 0x6d, 0x54, 0x3b, 0x5c, 0x8, 0xa2, 0x1b, 0x12, 0x21, 0xd0, 0xc, 0x90, 0x4c, 0x2b, 0x14, 0xd1, 0x99, 0x30, 0xdd, 0x51, 0xac, 0xff, 0x8b, 0x68, 0xe, 0xc2, 0x4d, 0x52, 0x6f, 0x54, 0x9e, 0xdb, 0xb5, 0x46, 0x9f, 0x1d, 0x71, 0x86, 0x4, 0x42, 0x98, 0xff, 0x4d, 0xc8, 0x4f, 0x9c, 0xbf, 0x9f, 0xfb, 0xc3, 0xc, 0x99, 0x47, 0x3f, 0xef, 0x11, 0xcb, 0xcb, 0x26, 0x46, 0x56, 0x99, 0x2e, 0xe4, 0x7a, 0xcf, 0xc, 0x5d, 0xee, 0x1, 0x71, 0x40, 0x23, 0x81, 0x79, 0x44, 0xe1, 0x4a, 0x31, 0xe0, 0x92, 0x14, 0xb1, 0x27, 0xd7, 0x61, 0xd9, 0xe2, 0x8a, 0xd0, 0xf4, 0x77, 0x64, 0x1c, 0xaa, 0xe0, 0xfd, 0x92, 0x5b, 0x9, 0xea, 0x91, 0x21, 0x46, 0xd7, 0xcb, 0x6, 0xda, 0xdb, 0x47, 0x17, 0xdb, 0xb0, 0x9d, 0xca, 0x6, 0x44, 0xbc, 0x1, 0x6f, 0x4, 0x2f, 0xd0, 0xb4, 0xae, 0xc8, 0xcb, 0x76, 0x7f, 0xb1, 0xc2, 0xa1, 0x59, 0x79, 0x76, 0x85, 0xc, 0xaf, 0xc3, 0x3a, 0x59, 0x1c, 0x93, 0x75, 0xb9, 0xa7, 0x31, 0xad, 0x95, 0x74, 0x92, 0xe5, 0xe2, 0x59, 0x4c, 0x65, 0xb0, 0x80, 0xe8, 0xb7, 0x15, 0xa9, 0xcd, 0x56, 0x58, 0xb0, 0x72, 0x74, 0xee, 0x12, 0x3, 0x45, 0x5, 0x5f, 0x75, 0x44, 0x88, 0x46, 0x96, 0x18, 0x6d, 0xbc, 0x47, 0xe7, 0x2e, 0x99, 0x4b, 0x85, 0x9e, 0x38, 0xf8, 0x7d, 0x5c, 0x65, 0x4, 0xd1, 0xd3, 0x7d, 0x39, 0x63, 0x20, 0xe3, 0x37, 0x2, 0xc, 0xe5, 0x68, 0xf0, 0xf4, 0xd8, 0xf2, 0x9f, 0x69, 0x17, 0x6f, 0xb1, 0xe8, 0x36, 0x6, 0xd5, 0x4a, 0x2a, 0x98, 0xaf, 0x67, 0x28, 0x89, 0x70, 0xfd, 0x3b, 0x1e, 0x5a, 0x35, 0x61, 0xc3, 0x1c, 0xee, 0x1c, 0x45, 0xf, 0xa2, 0xdc, 0xa7, 0xaa, 0x8b, 0x30, 0xdb, 0xa5, 0x35, 0x3b, 0x45, 0xb1, 0x8d, 0x88, 0x41, 0xcc, 0x7b, 0x5d, 0xd6, 0x21, 0x67, 0xfc, 0x25, 0x97, 0xeb, 0x9d, 0x94, 0xf9, 0x8a, 0xc, 0x4d, 0x79, 0x2e, 0xea, 0xcc, 0xad, 0x4d, 0x27, 0xab, 0x1f, 0x4e, 0x35, 0xf1, 0xe5, 0x6b, 0xf1, 0x96, 0xf3, 0xe1, 0xbc, 0xda, 0xe, 0xa, 0xf1, 0x86, 0x72, 0xbe, 0x2b, 0xf6, 0xd5, 0xf1, 0x5c, 0x8b, 0x77, 0xe1, 0x16, 0x34, 0xc4, 0x5d, 0xe6, 0xbe, 0x67, 0x17, 0x3d, 0x3c, 0x22, 0x77, 0xef, 0x36, 0x3f, 0xb5, 0x1f, 0x7f, 0x6e, 0xf8, 0x2b, 0xa4, 0x62, 0x45, 0x44, 0xf2, 0x23, 0x36, 0x88, 0x91, 0xd4, 0x26, 0x4c, 0xf4, 0x13, 0x84, 0xe8, 0xd5, 0xdd, 0x93, 0xa1, 0x3c, 0x8a, 0x1, 0x52, 0x72, 0x90, 0x62, 0x3f, 0xf3, 0x0, 0x3d, 0xf, 0xd0, 0xbf, 0xdb, 0xf1, 0xd, 0x9f, 0x17, 0xf0, 0xe9, 0x3c, 0x3, 0xc3, 0xcf, 0x40, 0xa0, 0x2f, 0x8, 0x82, 0xea, 0x41, 0xde, 0xed, 0x53, 0xd4, 0x44, 0xa3, 0x47, 0xc6, 0x94, 0x13, 0xd6, 0xae, 0x33, 0x6f, 0x9c, 0x38, 0x22, 0x42, 0x95, 0x53, 0xb8, 0x92, 0x2f, 0xbb, 0x73, 0xc1, 0x7e, 0x25, 0x76, 0xbb, 0x79, 0x9f, 0x9, 0x57, 0xe0, 0xb1, 0xa5, 0x17, 0xb3, 0x9d, 0x3e, 0x9c, 0xcf, 0x16, 0x9b, 0xaa, 0x16, 0x21, 0xef, 0xeb, 0xe3, 0xb6, 0xf8, 0x49, 0x1, 0x7e, 0x9e, 0x83, 0xe3, 0x18, 0xa9, 0xe0, 0xe7, 0xbc, 0xe0, 0x81, 0x7a, 0x5, 0x39, 0xfe, 0xb4, 0x8e, 0xfb, 0xf2, 0x41, 0x78, 0xb9, 0x19, 0x52, 0x82, 0x4d, 0x62, 0xd2, 0x6c, 0xe3, 0xea, 0xa4, 0x1c, 0x41, 0xcb, 0x11, 0x34, 0x75, 0xa8, 0xf9, 0x70, 0x2c, 0xf7, 0xcf, 0xe2, 0x41, 0x53, 0xc6, 0x3e, 0xf7, 0x38, 0x2f, 0x2f, 0x75, 0xd9, 0xbd, 0x2, 0x93, 0xa7, 0xe9, 0x74, 0x5a, 0xde, 0x5f, 0x1, 0xc3, 0x6d, 0x9a, 0xf, 0x54, 0xe9, 0xdc, 0x2, 0x1c, 0xe5, 0x8, 0x52, 0x51, 0x1, 0x1a, 0x60, 0x28, 0x22, 0x3, 0xcb, 0x63, 0x19, 0xf3, 0x58, 0x46, 0x25, 0x64, 0x0, 0x83, 0x87, 0x42, 0xd0, 0x64, 0x8c, 0x4b, 0x0, 0xd, 0x4b, 0xb3, 0xc0, 0x3c, 0x9a, 0x35, 0x8f, 0x66, 0x95, 0x9c, 0x12, 0xbd, 0x48, 0xe3, 0xa7, 0xe0, 0x9a, 0xf7, 0x14, 0x9a, 0xe4, 0x24, 0x81, 0x95, 0x77, 0x23, 0x96, 0x77, 0x23, 0x46, 0x5e, 0xfd, 0xb9, 0xa1, 0x7, 0x32, 0x8a, 0xc5, 0xfa, 0xa5, 0xbc, 0x78, 0x59, 0xb1, 0xd3, 0x65, 0x32, 0xdf, 0xd, 0xcf, 0x6b, 0x25, 0x38, 0x50, 0x94, 0x1c, 0xe5, 0xd0, 0x69, 0xa0, 0x5d, 0xf5, 0xf3, 0x5c, 0x8, 0x5a, 0x8e, 0xa0, 0x25, 0x6d, 0x40, 0xa7, 0xa, 0xc8, 0x37, 0xbf, 0xee, 0xaf, 0x40, 0x7, 0x1b, 0xa0, 0xf9, 0x88, 0xd8, 0x0, 0x5d, 0x80, 0x6b, 0x3, 0xfc, 0x54, 0x54, 0x80, 0x98, 0xd, 0xf0, 0x61, 0x79, 0x2c, 0x63, 0x1e, 0xcb, 0x8, 0x6c, 0x80, 0x82, 0xf9, 0x36, 0x20, 0x48, 0xc6, 0xb8, 0xc4, 0x6d, 0x40, 0x0, 0xcc, 0xa3, 0x59, 0xf3, 0x68, 0xd6, 0xb8, 0xd, 0x50, 0xf8, 0x29, 0x78, 0xca, 0x6, 0xb8, 0x5a, 0x9b, 0xc0, 0xca, 0xbb, 0x11, 0xcb, 0xbb, 0x11, 0x23, 0x6f, 0xe8, 0xdc, 0xd0, 0x3, 0x3d, 0x1b, 0xa0, 0xb3, 0xd2, 0x36, 0x40, 0xdf, 0xa9, 0x8d, 0x76, 0x21, 0xb9, 0x84, 0x9e, 0xe0, 0x40, 0x6f, 0x4b, 0xc0, 0x16, 0xd6, 0x69, 0xa0, 0x5d, 0xf5, 0x85, 0x57, 0x4, 0x2d, 0x47, 0xd0, 0x92, 0x36, 0xa0, 0x53, 0x5, 0xe4, 0x33, 0x7d, 0xf7, 0x57, 0xa0, 0x83, 0xd, 0x40, 0x2e, 0x27, 0xfb, 0x36, 0x40, 0x17, 0xe0, 0xda, 0x0, 0x3f, 0x15, 0x15, 0x20, 0x66, 0x3, 0x7c, 0x58, 0x1e, 0xcb, 0x98, 0xc7, 0x32, 0x2, 0x1b, 0xa0, 0x60, 0xbe, 0xd, 0x8, 0x92, 0x31, 0x2e, 0x71, 0x1b, 0x10, 0x0, 0xf3, 0x68, 0xd6, 0x3c, 0x9a, 0x35, 0x6e, 0x3, 0xf4, 0xa5, 0xec, 0x4, 0x3c, 0x65, 0x3, 0x5c, 0xad, 0x4d, 0x60, 0xe5, 0xdd, 0x88, 0xe5, 0xdd, 0x88, 0x51, 0x36, 0xe0, 0x96, 0x1e, 0xe8, 0xd9, 0x0, 0x9d, 0x95, 0xb6, 0x1, 0xe2, 0x6, 0x75, 0xdc, 0x0, 0x88, 0xcb, 0xd4, 0x89, 0xe2, 0x39, 0x19, 0x47, 0x2d, 0x44, 0x2, 0x68, 0x4e, 0x71, 0xc9, 0xd9, 0x47, 0xc8, 0x7d, 0x84, 0x64, 0x8f, 0x4f, 0xb3, 0x2b, 0x9f, 0xd2, 0xbc, 0x87, 0xdd, 0xe, 0x1d, 0xdd, 0xbf, 0x6f, 0xee, 0xf7, 0x72, 0x41, 0xd7, 0xed, 0xe2, 0x4e, 0x52, 0x28, 0x22, 0xac, 0x73, 0x3b, 0x80, 0x9c, 0xcc, 0x92, 0x93, 0x59, 0x40, 0x9f, 0xe6, 0x0, 0xbf, 0x43, 0xbb, 0x69, 0x1, 0x4f, 0x78, 0x57, 0x76, 0x21, 0x39, 0x9d, 0x29, 0xa7, 0x33, 0xc5, 0x7b, 0xb0, 0xb8, 0x49, 0x1f, 0x3, 0xa6, 0xfa, 0x2e, 0xd0, 0xb9, 0x18, 0x4a, 0xde, 0x81, 0x4c, 0xde, 0x81, 0xc, 0xd9, 0x5f, 0xbb, 0x76, 0x18, 0xbf, 0xb3, 0xaa, 0x7c, 0x74, 0x67, 0xd5, 0x37, 0xd9, 0xa3, 0x1d, 0x40, 0x3d, 0x95, 0x1c, 0x2f, 0x5e, 0xef, 0xfb, 0xc2, 0x66, 0xd4, 0x69, 0xa0, 0xfd, 0xf4, 0x35, 0x73, 0x4, 0x2d, 0x47, 0xd0, 0x92, 0xdd, 0xb7, 0x53, 0x5, 0xe4, 0xdb, 0xb5, 0xf7, 0x57, 0xa0, 0x43, 0x3f, 0x46, 0x42, 0x2, 0xf8, 0x5d, 0x59, 0x17, 0xe0, 0xf6, 0x66, 0x3f, 0x15, 0x15, 0x20, 0xd6, 0xa7, 0x7d, 0x58, 0x1e, 0xcb, 0x98, 0xc7, 0x32, 0x82, 0xce, 0xad, 0x60, 0x7e, 0xff, 0xe, 0x92, 0x31, 0x2e, 0xf1, 0x5e, 0x1e, 0x0, 0xf3, 0x68, 0xd6, 0x3c, 0x9a, 0x35, 0xde, 0xdd, 0x75, 0x28, 0x84, 0x4, 0x3c, 0xd5, 0xe9, 0x5d, 0xad, 0x4d, 0x60, 0xe5, 0xdd, 0x88, 0xe5, 0xdd, 0x88, 0x51, 0x6, 0xe0, 0x96, 0x1e, 0xe8, 0xd9, 0x0, 0x9d, 0x95, 0xb6, 0x1, 0x2a, 0x42, 0x41, 0x7c, 0xde, 0x2e, 0x36, 0x9c, 0x53, 0x2b, 0x7, 0x82, 0x90, 0xbb, 0xa6, 0x23, 0x93, 0xe0, 0x6a, 0x8c, 0xc, 0x20, 0x10, 0x22, 0xe5, 0x21, 0x52, 0x7a, 0xd9, 0xae, 0x3, 0xeb, 0xf2, 0xa5, 0xe9, 0x7b, 0x59, 0xef, 0xb2, 0x66, 0x17, 0x44, 0x78, 0x8, 0x96, 0xec, 0x24, 0x75, 0x6f, 0xc5, 0xce, 0x4d, 0xc4, 0xc4, 0x86, 0xae, 0xd7, 0xb9, 0xa0, 0x3c, 0x92, 0x2d, 0x8f, 0x64, 0x83, 0x8b, 0x75, 0x2, 0x14, 0xac, 0xd5, 0x79, 0xa9, 0x8, 0x7f, 0xc4, 0x4a, 0x9d, 0x7, 0xcb, 0x63, 0x19, 0xf3, 0x58, 0xc6, 0xc4, 0x32, 0x9d, 0x8c, 0x67, 0x11, 0x7, 0x27, 0x17, 0xe9, 0xa0, 0x7e, 0xc6, 0x91, 0xf2, 0x4e, 0xa4, 0xf2, 0x4e, 0xa4, 0xc8, 0xc9, 0x79, 0xf7, 0x6e, 0xe6, 0xcf, 0xcd, 0x55, 0x4e, 0xba, 0x9b, 0xd7, 0xd5, 0xfe, 0x57, 0x6f, 0x26, 0xef, 0xdf, 0xea, 0x8, 0x1e, 0xe6, 0xd4, 0xf9, 0xfa, 0xe6, 0xcb, 0x51, 0x3, 0x9e, 0x90, 0xfb, 0x9, 0xe9, 0x7d, 0xa, 0xc9, 0x4a, 0xf4, 0x89, 0xd0, 0x9b, 0x76, 0x1f, 0x5c, 0xe, 0x3, 0x86, 0xa0, 0x8e, 0x89, 0xdf, 0x4a, 0xfa, 0x51, 0x21, 0x47, 0x32, 0xba, 0x32, 0xf4, 0x77, 0x95, 0x58, 0x7d, 0xca, 0x13, 0xdf, 0x3a, 0x8a, 0xbe, 0x81, 0x7a, 0x45, 0xc4, 0xe5, 0x17, 0xd7, 0xb9, 0x27, 0x0, 0x5e, 0xa3, 0x28, 0xe, 0xfb, 0x30, 0x30, 0x2c, 0xb6, 0x29, 0x66, 0x36, 0x82, 0x9f, 0xf9, 0x2f, 0xc5, 0xd5, 0xcb, 0xe5, 0x8d, 0x4e, 0x80, 0x83, 0x12, 0x9a, 0x1d, 0x28, 0xc1, 0xde, 0xcf, 0xb8, 0xfb, 0x72, 0x2, 0x20, 0xfd, 0xb5, 0x1, 0xa4, 0xbf, 0x36, 0x96, 0x79, 0xb9, 0xeb, 0x76, 0x17, 0x65, 0xec, 0x0, 0x14, 0x3c, 0xe6, 0x62, 0x70, 0x1e, 0x0, 0xba, 0x7b, 0x42, 0xa, 0xde, 0x2b, 0x5d, 0x9e, 0xdb, 0xf6, 0xb0, 0xff, 0x64, 0x71, 0x9d, 0x2b, 0x36, 0x25, 0x6b, 0x4a, 0x2, 0xd6, 0x9c, 0x97, 0xbb, 0xa, 0x2, 0xdd, 0xc3, 0x36, 0xc5, 0xba, 0xbc, 0xe8, 0x7d, 0xbe, 0xc, 0xbb, 0x5b, 0xad, 0x80, 0xe2, 0x66, 0x72, 0x8f, 0xd7, 0xbc, 0x38, 0x79, 0xb7, 0xa5, 0x31, 0x8c, 0x38, 0x58, 0x96, 0x3b, 0xac, 0xf6, 0x17, 0x70, 0x63, 0x77, 0xc5, 0x9f, 0xf5, 0x3d, 0x36, 0xf6, 0x89, 0x64, 0xa9, 0x62, 0x3a, 0x99, 0x63, 0xbb, 0x31, 0x8, 0xda, 0x13, 0xa, 0x54, 0x31, 0x2b, 0xe, 0x5f, 0xae, 0x22, 0x1c, 0x46, 0x1c, 0x47, 0x2a, 0x80, 0x29, 0x85, 0x8f, 0xcc, 0xc3, 0x33, 0x33, 0xaa, 0xa9, 0x33, 0x13, 0x25, 0xc8, 0xc4, 0x8, 0xa, 0xc4, 0x35, 0x38, 0x32, 0xc7, 0x5f, 0x9e, 0x58, 0x8d, 0x64, 0xa6, 0xfe, 0xe7, 0xaa, 0xa9, 0x96, 0x55, 0xcd, 0xea, 0xe8, 0x4a, 0x2d, 0x86, 0xd8, 0x91, 0x5c, 0x58, 0xf8, 0xfa, 0xac, 0x7a, 0xe7, 0x70, 0xe2, 0xdf, 0x69, 0xf7, 0x60, 0x74, 0xa6, 0x90, 0x6a, 0x5b, 0xed, 0xf8, 0x2e, 0xfb, 0xe6, 0xbc, 0x97, 0x27, 0x1f, 0xf8, 0x7d, 0x75, 0x8f, 0x38, 0x8a, 0x92, 0x80, 0x33, 0xa1, 0x33, 0x13, 0xd7, 0xc6, 0xe, 0xd8, 0x65, 0x56, 0xf4, 0x4e, 0xdc, 0x6d, 0xd6, 0x7, 0xf1, 0xf3, 0x1b, 0x20, 0x88, 0x30, 0x8f, 0x6d, 0xb1, 0x2e, 0x9a, 0x6d, 0xb9, 0x5e, 0x38, 0x1, 0x58, 0xa6, 0xb1, 0x20, 0x6, 0x32, 0x54, 0x38, 0x86, 0x71, 0x35, 0x43, 0xba, 0xbe, 0xf8, 0x3a, 0x1f, 0xb1, 0xab, 0x17, 0xde, 0xb0, 0xcf, 0x3b, 0xce, 0x90, 0x1, 0x84, 0x5d, 0xb9, 0x3f, 0x13, 0x37, 0x2c, 0x44, 0xbc, 0x7, 0x75, 0xeb, 0x4c, 0xdf, 0xb1, 0x60, 0x69, 0xd9, 0x2, 0x76, 0x8c, 0x85, 0x7d, 0x57, 0x2, 0xc4, 0x4d, 0x19, 0xcd, 0x33, 0xef, 0xa2, 0x12, 0xf, 0xee, 0xd1, 0xd8, 0xc7, 0xe4, 0xf7, 0xa5, 0x7f, 0x8a, 0xc4, 0xb, 0xef, 0x9d, 0xdc, 0x8f, 0xf, 0xe3, 0x3c, 0x80, 0xc, 0x75, 0x75, 0xcc, 0xed, 0x35, 0xbd, 0xaf, 0x8b, 0x8, 0xcc, 0x93, 0xc5, 0x50, 0x3c, 0x31, 0x20, 0x9a, 0xe8, 0xa2, 0x2f, 0x98, 0x80, 0x48, 0xf7, 0xe, 0x6e, 0x8f, 0xd, 0x4f, 0x3f, 0x57, 0x3c, 0xca, 0x0, 0x78, 0xb9, 0x58, 0x85, 0x34, 0x79, 0x1a, 0xca, 0x5a, 0xfb, 0x5d, 0x95, 0x8e, 0x19, 0xed, 0x90, 0x7e, 0xae, 0xab, 0xe7, 0x82, 0x78, 0xa4, 0x9d, 0x9f, 0xc1, 0x10, 0x57, 0x61, 0x57, 0x35, 0xb3, 0x61, 0x3c, 0xd6, 0xf7, 0x36, 0x11, 0x6a, 0x43, 0x9d, 0xcb, 0xc5, 0xc2, 0x5f, 0x85, 0xa5, 0x6a, 0xb7, 0x8e, 0x40, 0xa4, 0x43, 0xc6, 0x5c, 0xf0, 0x22, 0x75, 0x2, 0x58, 0x47, 0xb5, 0x75, 0xa9, 0xea, 0xe0, 0xb9, 0x45, 0x9f, 0x2, 0xe0, 0xdc, 0x58, 0x70, 0xa7, 0x53, 0x33, 0xb, 0xf4, 0x74, 0x8c, 0x33, 0x2e, 0xa, 0x38, 0xd3, 0x3, 0x12, 0x84, 0x37, 0xb, 0x22, 0xb8, 0x3, 0x8, 0xe, 0x7f, 0x78, 0x53, 0xdf, 0x41, 0xf, 0xad, 0x64, 0xfc, 0xd, 0x7b, 0xf4, 0x54, 0x90, 0x3a, 0x4d, 0xc3, 0xac, 0xfb, 0x4b, 0xb5, 0xce, 0xff, 0xc7, 0xff, 0xf9, 0x9f, 0x1c, 0xf4, 0xbf, 0x79, 0x36, 0x7e, 0x2, 0x6e, 0xf8, 0x97, 0x6a, 0x75, 0x3a, 0x34, 0x87, 0x4d, 0x3b, 0x7c, 0xe1, 0xdd, 0x8d, 0xd1, 0xf9, 0xa9, 0xdc, 0xb, 0x4e, 0x7e, 0xde, 0x14, 0x75, 0x53, 0xbe, 0x5f, 0x60, 0x77, 0x68, 0xbd, 0x99, 0xa7, 0xb0, 0x30, 0xae, 0xc7, 0x94, 0x28, 0x5, 0x69, 0x90, 0x54, 0xff, 0x33, 0xfd, 0x6e, 0x61, 0x2e, 0xbb, 0xba, 0x68, 0x1c, 0xe1, 0xa2, 0x2c, 0x14, 0x7c, 0x13, 0xc4, 0x60, 0xf1, 0x40, 0x58, 0x4c, 0x5c, 0x89, 0x7e, 0xd4, 0x29, 0x4e, 0x4d, 0xb4, 0xf3, 0x70, 0xe9, 0xf2, 0x1f, 0xd6, 0x92, 0x6e, 0xaa, 0xaf, 0xcc, 0xe2, 0x3b, 0xbc, 0xf1, 0xf9, 0x8a, 0x3e, 0x7, 0x28, 0xce, 0x8e, 0x6a, 0xa3, 0xfa, 0xf4, 0xc4, 0x6a, 0x66, 0xed, 0x8e, 0x2f, 0x3b, 0xc2, 0xc, 0xf1, 0x23, 0xcf, 0xc2, 0x73, 0xf5, 0x87, 0xfb, 0xe2, 0xf3, 0xb2, 0x38, 0xd, 0x44, 0x99, 0xea, 0xb0, 0x61, 0xcf, 0x10, 0x51, 0x58, 0x4e, 0xe0, 0x7b, 0x2f, 0xba, 0x94, 0xf1, 0x34, 0xb, 0x7e, 0xd2, 0x91, 0x35, 0x73, 0xfe, 0xee, 0x9d, 0x2d, 0xc4, 0xe1, 0x26, 0x59, 0x98, 0xcb, 0x3b, 0x2f, 0x4d, 0xb4, 0xa0, 0x39, 0x5d, 0x1f, 0x3e, 0xcc, 0x10, 0x3d, 0xf4, 0xa9, 0x4a, 0x13, 0x32, 0xf0, 0x89, 0x23, 0xfa, 0x11, 0x41, 0xa7, 0xb4, 0x5, 0xc, 0xc0, 0xfb, 0x60, 0x2c, 0xae, 0x1d, 0x7b, 0xd7, 0x48, 0x5, 0xc4, 0x81, 0xec, 0x90, 0x20, 0x18, 0xe2, 0xab, 0x23, 0xe8, 0xfc, 0x28, 0x5c, 0x58, 0xa, 0x7c, 0xb0, 0x89, 0xa0, 0xe2, 0x4c, 0x6e, 0x11, 0x78, 0x9e, 0x82, 0x83, 0x19, 0x1c, 0x6, 0x6, 0x8b, 0x2e, 0x96, 0xd5, 0xb0, 0x50, 0xa2, 0x2c, 0xbc, 0x8, 0x40, 0xf9, 0x62, 0x6e, 0x6e, 0x82, 0x1a, 0x8a, 0xf9, 0xdf, 0x83, 0x27, 0x23, 0x9b, 0x18, 0x34, 0x54, 0xcf, 0x7e, 0xa2, 0xb9, 0x0, 0x8, 0x3d, 0x32, 0xad, 0xe, 0x65, 0xb2, 0x7e, 0x71, 0xe0, 0x31, 0x34, 0x5d, 0xe8, 0xcc, 0x83, 0xf6, 0x7c, 0x16, 0x4c, 0x3a, 0xbc, 0x23, 0xe1, 0xb7, 0x9c, 0x42, 0x2, 0xd, 0xf, 0x53, 0x10, 0x72, 0xcf, 0xe, 0x39, 0xe7, 0x7d, 0x19, 0xcd, 0x10, 0x90, 0x25, 0x33, 0xbe, 0x3f, 0xc1, 0x60, 0x8a, 0xef, 0x65, 0x8a, 0x8d, 0x84, 0x27, 0x13, 0xfc, 0x41, 0xe1, 0xfb, 0xb, 0x3d, 0x13, 0x55, 0x4d, 0x7, 0x2, 0x34, 0x7a, 0xe7, 0xf5, 0x69, 0xcc, 0x1b, 0xb, 0x57, 0xf, 0x2c, 0x88, 0xfe, 0x68, 0xc7, 0x74, 0xd6, 0x56, 0x79, 0x90, 0xa0, 0x64, 0x5b, 0x50, 0x28, 0x7, 0x47, 0xeb, 0xfc, 0x21, 0x71, 0x80, 0xed, 0x71, 0xc4, 0x6b, 0x8a, 0x32, 0xe4, 0x0, 0x7c, 0x7e, 0x8, 0xd, 0xf0, 0x11, 0x3a, 0xb4, 0x99, 0x34, 0xb, 0x89, 0x26, 0x52, 0xd4, 0x62, 0xe2, 0xf7, 0xc5, 0xd4, 0xbf, 0x87, 0x84, 0x27, 0xbc, 0x37, 0x6a, 0x3c, 0x55, 0x74, 0xac, 0x9, 0x43, 0x45, 0x7c, 0x65, 0x2b, 0xf5, 0x2, 0x45, 0x8, 0xec, 0x96, 0x18, 0x9d, 0x4, 0x78, 0x70, 0xb0, 0xe2, 0x56, 0xe3, 0x21, 0x40, 0x75, 0xee, 0xd3, 0x7c, 0x4, 0x21, 0x43, 0xd4, 0xcb, 0x66, 0x61, 0x27, 0x16, 0xf7, 0xca, 0xa3, 0x64, 0x46, 0xe3, 0x80, 0xce, 0x68, 0xec, 0x10, 0xc2, 0xf9, 0xb6, 0xb, 0x98, 0xb7, 0xac, 0x51, 0xea, 0x41, 0x3, 0xd2, 0xed, 0xc5, 0x55, 0xb, 0x38, 0xa2, 0x50, 0x17, 0xdf, 0xd5, 0xc9, 0xf0, 0xcc, 0xe, 0x1c, 0x22, 0xd8, 0x59, 0x4f, 0xe1, 0x77, 0xf1, 0x90, 0x2e, 0x80, 0x76, 0xd5, 0xcf, 0xbe, 0x53, 0x75, 0xc7, 0x7d, 0xe0, 0x1, 0x13, 0xf2, 0xd1, 0xa8, 0x6b, 0x17, 0xb2, 0x96, 0x10, 0x89, 0xfe, 0x10, 0xad, 0xc2, 0x43, 0xe7, 0x7a, 0x3c, 0x74, 0x10, 0x5, 0xe2, 0xdb, 0x44, 0x14, 0x26, 0x3b, 0x1b, 0xd, 0xcd, 0xb6, 0xe7, 0xe8, 0xd3, 0xe6, 0x28, 0x62, 0x89, 0xfc, 0x31, 0x45, 0xc4, 0x92, 0x5c, 0x48, 0xdb, 0xb0, 0xe8, 0x62, 0x52, 0xb0, 0x4e, 0x4f, 0x33, 0x12, 0xb3, 0x2b, 0x5d, 0xcd, 0x8, 0x6d, 0xda, 0xba, 0x31, 0xf1, 0x66, 0xe6, 0x1e, 0x25, 0x7b, 0xa7, 0xdd, 0xbf, 0x83, 0xd6, 0x3d, 0xe, 0xe0, 0xa6, 0xd6, 0x7a, 0x8d, 0x2f, 0xb8, 0xb3, 0xa1, 0xfe, 0x7e, 0x6e, 0xda, 0x6a, 0x53, 0x95, 0x6b, 0x77, 0x39, 0x16, 0x1a, 0x7, 0xb9, 0x3e, 0xcb, 0x40, 0xcc, 0xf8, 0xab, 0x29, 0x9d, 0xdd, 0x86, 0x11, 0xab, 0xb9, 0x79, 0x53, 0xb2, 0x19, 0x76, 0xd1, 0x96, 0x28, 0xe5, 0xc0, 0x92, 0xb9, 0x10, 0x67, 0xb4, 0x40, 0xbc, 0xac, 0xa4, 0xd9, 0xf9, 0xf1, 0x9a, 0x20, 0x23, 0xaf, 0xd4, 0xe0, 0xa6, 0xc, 0xc7, 0x27, 0x66, 0x53, 0xd7, 0x5f, 0xd6, 0x45, 0x5b, 0xa8, 0x96, 0x56, 0xb, 0xfe, 0xcd, 0x27, 0x91, 0x13, 0xbf, 0x3, 0xda, 0xd, 0x5f, 0x45, 0xfa, 0xa2, 0x91, 0x81, 0x89, 0xbd, 0xb5, 0x1c, 0x22, 0x2b, 0x19, 0xe0, 0x4e, 0x2c, 0x2, 0x9e, 0xca, 0x55, 0xab, 0xee, 0x30, 0x65, 0xef, 0x63, 0x31, 0x5f, 0x64, 0x2b, 0xd1, 0xf3, 0x40, 0xa9, 0x36, 0xb4, 0x62, 0x0, 0x2a, 0xee, 0x13, 0x5b, 0xa0, 0xe1, 0xbb, 0x45, 0xf9, 0x42, 0xae, 0x4f, 0x23, 0x7c, 0xd9, 0x80, 0x38, 0x60, 0x71, 0x96, 0xc, 0x8, 0x9d, 0xf9, 0x31, 0x26, 0x9f, 0xbd, 0xeb, 0xd9, 0x3e, 0x14, 0xb9, 0x94, 0x1d, 0x43, 0x61, 0x6d, 0x22, 0x8d, 0xdb, 0xf7, 0x8e, 0x36, 0x45, 0xf0, 0x4f, 0xe0, 0x84, 0xb5, 0xe8, 0x80, 0x88, 0xd6, 0xa5, 0x6b, 0x58, 0xab, 0x28, 0x7f, 0x11, 0x6c, 0x8a, 0xd3, 0x8e, 0x59, 0x34, 0xcf, 0x7e, 0x4c, 0x2d, 0x82, 0x1d, 0x12, 0x2b, 0x64, 0xa3, 0x13, 0xaa, 0x2f, 0x32, 0xb9, 0x80, 0xe5, 0xc6, 0x5e, 0x8d, 0x69, 0x1c, 0x87, 0x26, 0x34, 0xce, 0x47, 0xf1, 0x8b, 0x7c, 0xfb, 0x88, 0x78, 0x4, 0xe3, 0x4, 0x4e, 0x27, 0x55, 0xeb, 0x54, 0x89, 0xae, 0xa1, 0xf7, 0xa2, 0xfc, 0x45, 0xb0, 0x6f, 0x54, 0x35, 0x8a, 0x67, 0x5c, 0x33, 0x2, 0x76, 0x48, 0xac, 0x8e, 0xaa, 0x96, 0x12, 0x59, 0xa0, 0x6a, 0xbd, 0x88, 0x9e, 0x21, 0x7a, 0x5, 0xa7, 0x10, 0xf0, 0xa9, 0x43, 0x92, 0x62, 0x87, 0x71, 0x1e, 0x52, 0xe8, 0xcd, 0xb9, 0xee, 0x1d, 0xb1, 0x77, 0xa8, 0xae, 0x1e, 0x6c, 0x60, 0xf7, 0xc0, 0x89, 0x15, 0xce, 0x30, 0x1a, 0x4c, 0xea, 0xc2, 0xb8, 0x7f, 0x8c, 0xc7, 0xe9, 0x7a, 0xc8, 0x1d, 0xf9, 0xc4, 0x56, 0x60, 0xb7, 0x78, 0xf0, 0x8, 0xa3, 0x41, 0x8c, 0x4d, 0xd2, 0x38, 0x74, 0xa6, 0xd5, 0xe5, 0xc4, 0x49, 0x9a, 0x18, 0x11, 0x6a, 0x23, 0x8a, 0xe7, 0xbc, 0xa8, 0xa0, 0x9f, 0xb7, 0xa5, 0x35, 0xd5, 0x79, 0xb6, 0x25, 0x54, 0x49, 0x12, 0xec, 0xd, 0xc1, 0xd5, 0x0, 0x37, 0x85, 0x1, 0xc6, 0x67, 0x9, 0x64, 0x6f, 0xa2, 0x11, 0x62, 0x83, 0x7, 0x3e, 0xfc, 0x9, 0x96, 0x3f, 0xfb, 0x49, 0x66, 0xfe, 0xde, 0x6b, 0x95, 0x51, 0xb9, 0x6, 0xef, 0xb1, 0xd0, 0x8d, 0x5, 0x67, 0x71, 0x21, 0x4d, 0xa, 0x4a, 0x37, 0x4, 0x31, 0xb7, 0x4a, 0x67, 0xc7, 0xd6, 0x58, 0x13, 0x32, 0xee, 0xd8, 0x82, 0x1d, 0x70, 0xe3, 0x73, 0xd0, 0xae, 0x2b, 0x81, 0x31, 0xf9, 0xf9, 0xcf, 0x10, 0xf9, 0xd6, 0x11, 0xd9, 0xa4, 0x31, 0x5d, 0x1b, 0xdf, 0x21, 0x44, 0xdd, 0x13, 0x72, 0x60, 0x3, 0xc3, 0x13, 0xeb, 0x3a, 0xc8, 0x6e, 0x5, 0x86, 0x6b, 0x56, 0x31, 0x51, 0xa0, 0xda, 0x83, 0x41, 0x61, 0xc1, 0x4e, 0xcc, 0x5b, 0xf5, 0xf6, 0x8b, 0x17, 0x88, 0x6, 0x61, 0xfd, 0x4e, 0x5d, 0x41, 0x64, 0xb2, 0x2f, 0x3e, 0x5f, 0xa8, 0xd8, 0x34, 0x6a, 0x4a, 0xe5, 0x9d, 0x3f, 0x11, 0x79, 0x9e, 0xeb, 0x2a, 0x15, 0x1d, 0x5e, 0xe3, 0x3d, 0x17, 0xc9, 0x38, 0xf2, 0xf0, 0xad, 0xf7, 0x9e, 0xc, 0x45, 0xaf, 0xf3, 0xea, 0x26, 0x30, 0xbf, 0x6f, 0xd9, 0xc7, 0x37, 0xaf, 0xb8, 0xc9, 0xdc, 0xe0, 0x38, 0xc0, 0x25, 0x85, 0xe0, 0x96, 0x4b, 0x1e, 0x4c, 0x88, 0x1c, 0xae, 0x8c, 0x1f, 0x2b, 0xc0, 0xf6, 0xff, 0x59, 0x59, 0x3d, 0xb5, 0xc3, 0xdf, 0x87, 0x3f, 0x0, 0x2f, 0x26, 0x29, 0x7e, 0xf3, 0x5f, 0xd1, 0x62, 0x7f, 0xd, 0xde, 0xe2, 0xa4, 0x4d, 0x39, 0xe3, 0x7f, 0x6c, 0xa3, 0x3c, 0x57, 0xbb, 0x97, 0x8b, 0x5d, 0xff, 0x35, 0x5a, 0xc1, 0xa3, 0x9a, 0x35, 0x17, 0xea, 0x1, 0x26, 0xe7, 0x30, 0x96, 0xc6, 0xe6, 0x8a, 0x4, 0x4f, 0x42, 0x39, 0xaa, 0x68, 0x54, 0x54, 0xa3, 0xb2, 0x86, 0x73, 0x3a, 0xc7, 0x38, 0x15, 0x45, 0xa7, 0xeb, 0x10, 0xc7, 0x29, 0x3, 0x3b, 0x37, 0xac, 0x4, 0xab, 0x5f, 0x91, 0x22, 0x2b, 0x3, 0xe, 0xe6, 0x60, 0xa9, 0xa0, 0x29, 0x43, 0x98, 0xa3, 0x59, 0xe4, 0x81, 0x20, 0xfd, 0xfc, 0xf, 0xf1, 0x64, 0xa1, 0xb7, 0x88, 0x48, 0x6a, 0x9e, 0x8a, 0xfe, 0x60, 0x99, 0x17, 0x1f, 0x76, 0x69, 0xf, 0x2c, 0x7b, 0xf8, 0x8f, 0x81, 0x11, 0x59, 0x6c, 0x53, 0xba, 0xa, 0x11, 0x60, 0xb1, 0x56, 0xc, 0xc7, 0xaa, 0xe1, 0x63, 0x5b, 0x14, 0x81, 0xf4, 0x99, 0x9, 0xbb, 0x22, 0x17, 0x3d, 0x1f, 0x41, 0xd4, 0x21, 0xba, 0x94, 0x18, 0xab, 0x94, 0xbf, 0x3c, 0xd4, 0x9, 0xdb, 0x1e, 0x71, 0x21, 0x54, 0xd2, 0xaf, 0x7d, 0xa8, 0x60, 0x14, 0x86, 0xaf, 0x6c, 0x24, 0x1e, 0xd4, 0x77, 0xe4, 0xc5, 0xb4, 0x3b, 0x84, 0xc8, 0xea, 0x97, 0x78, 0x87, 0xed, 0x5f, 0xa6, 0xc2, 0x6e, 0x4f, 0xd1, 0x75, 0x96, 0xec, 0x1c, 0xab, 0xba, 0xf6, 0x4c, 0x94, 0xb, 0xb0, 0xf5, 0x74, 0xeb, 0xa1, 0xe1, 0xf, 0x2c, 0xaf, 0x77, 0xf2, 0xd5, 0x45, 0xf0, 0x6a, 0x17, 0x24, 0xc3, 0x2a, 0x85, 0xc0, 0xe0, 0x10, 0x1f, 0x7d, 0x4a, 0x8f, 0x13, 0x68, 0x5a, 0x6, 0xc6, 0x3b, 0xaa, 0x5, 0x1, 0x96, 0x45, 0x2c, 0xd1, 0x70, 0x33, 0x8c, 0x32, 0x14, 0xd7, 0xb4, 0x3d, 0xb8, 0xd7, 0xc, 0x7c, 0x8f, 0xde, 0x7f, 0x5b, 0xa7, 0xef, 0xdc, 0xd7, 0x81, 0x68, 0x48, 0xc3, 0x79, 0xaf, 0x2d, 0x88, 0x77, 0x8b, 0x2e, 0x5d, 0xe2, 0xfb, 0xf4, 0xff, 0x37, 0xeb, 0xfb, 0xff, 0x80, 0xa, 0x52, 0xfd, 0x9d, 0x65, 0x1e, 0xa8, 0x53, 0x7c, 0xe2, 0x95, 0xcc, 0xc1, 0xb1, 0xd8, 0xfb, 0x77, 0x19, 0x1c, 0x1c, 0x15, 0x40, 0x2e, 0x1c, 0xf4, 0xa, 0x3e, 0x7c, 0xf5, 0xf4, 0x37, 0x98, 0xef, 0xd9, 0x82, 0x93, 0x87, 0xf4, 0xb0, 0xa0, 0xa0, 0xee, 0x13, 0x3, 0xc8, 0x93, 0x9a, 0xc9, 0x93, 0x82, 0x81, 0x1d, 0x4b, 0x9f, 0x2d, 0x54, 0x87, 0x44, 0x81, 0x6d, 0x34, 0xe7, 0x8, 0xcd, 0x5d, 0x10, 0xf0, 0x1c, 0xb4, 0xb8, 0xfa, 0x50, 0x97, 0xfe, 0x59, 0x8c, 0x99, 0xff, 0xf0, 0x93, 0x48, 0x1, 0x87, 0x2e, 0xf1, 0x21, 0x5c, 0x22, 0xd6, 0x73, 0x26, 0x23, 0xed, 0x8d, 0x67, 0xb3, 0xbe, 0xfe, 0x6f, 0x38, 0x22, 0xa3, 0x3d, 0x13, 0xd8, 0xba, 0xc, 0xfb, 0x8c, 0xb4, 0x78, 0x31, 0x9a, 0x4f, 0x55, 0x44, 0x28, 0xc9, 0xa0, 0xba, 0xe2, 0x46, 0x8c, 0x7d, 0x89, 0x3a, 0x6d, 0x84, 0x1c, 0x59, 0x81, 0xa0, 0xc4, 0xce, 0x99, 0xd3, 0xce, 0xe7, 0x4f, 0x7c, 0x6e, 0x82, 0x1b, 0x39, 0x42, 0x47, 0xff, 0x50, 0xed, 0x8e, 0x87, 0x53, 0x5b, 0x30, 0x21, 0x82, 0xf5, 0x5e, 0x90, 0xea, 0xbd, 0xd3, 0x3, 0x66, 0x8, 0xaa, 0x9, 0x2d, 0x6e, 0x4a, 0x2, 0x2a, 0xc3, 0x15, 0x3f, 0xfc, 0xea, 0xe5, 0xf5, 0x8e, 0xc8, 0xb2, 0xca, 0xd3, 0x28, 0x32, 0x8, 0x33, 0x8a, 0x93, 0x7a, 0xf8, 0xe7, 0xcd, 0x98, 0x11, 0x53, 0x20, 0xf3, 0x40, 0x4c, 0x6, 0x3b, 0x19, 0x3, 0xa8, 0x97, 0x0, 0x65, 0xa3, 0x4e, 0x3f, 0x32, 0xf0, 0x7b, 0xf9, 0x5c, 0xe0, 0xe1, 0xc4, 0xf, 0x84, 0xcb, 0x89, 0x62, 0xcd, 0x52, 0x9a, 0x55, 0x71, 0x2c, 0xad, 0x3a, 0xbc, 0x25, 0x57, 0xe3, 0x2c, 0x13, 0x71, 0x56, 0xb9, 0xcd, 0x2a, 0xd8, 0x3c, 0x89, 0xe5, 0xab, 0xcf, 0x15, 0xb3, 0x8c, 0x1, 0x59, 0xa, 0x43, 0xf6, 0x71, 0x0, 0x8f, 0xe5, 0xf5, 0x72, 0x5d, 0xc2, 0x88, 0xba, 0x8b, 0x20, 0xec, 0x6e, 0xa4, 0x7f, 0xfc, 0x2b, 0x70, 0x9d, 0x79, 0x83, 0x9f, 0x6b, 0xa8, 0x80, 0x17, 0xe7, 0x8e, 0x8f, 0x77, 0x5a, 0x4b, 0xd8, 0x97, 0xb4, 0xd, 0x0, 0xd4, 0x2, 0x3b, 0x8c, 0x29, 0x46, 0xa8, 0x7, 0xfe, 0x9, 0x7a, 0xe7, 0xf0, 0x3b, 0xbc, 0x87, 0x34, 0xc9, 0xd2, 0xec, 0x24, 0x8a, 0x4a, 0xb0, 0xc8, 0x51, 0x9c, 0xd3, 0xf2, 0xae, 0x30, 0xb0, 0x42, 0x2e, 0xf6, 0x5, 0x30, 0x6f, 0x31, 0xca, 0x21, 0x21, 0x6d, 0xb5, 0x3d, 0xae, 0xbe, 0x64, 0xe, 0x61, 0xd, 0xd7, 0xf, 0xf4, 0x4a, 0x92, 0x5c, 0xdb, 0x18, 0xcd, 0xe2, 0xfb, 0xe3, 0x63, 0xf0, 0x54, 0x8c, 0x7c, 0x9a, 0x7, 0xd2, 0x5, 0x23, 0xb, 0x9b, 0x46, 0x2f, 0x3f, 0xb9, 0x99, 0xc5, 0x12, 0x89, 0x3b, 0x34, 0x48, 0x49, 0xfd, 0xd9, 0xaa, 0x64, 0xcf, 0xa1, 0xd5, 0xf, 0x11, 0xa4, 0xbe, 0xbb, 0x68, 0x61, 0x48, 0x6b, 0xdb, 0x30, 0xfa, 0x60, 0x24, 0x71, 0x58, 0xde, 0x89, 0x51, 0x1d, 0xfa, 0x65, 0x1e, 0xa1, 0xba, 0x7, 0x5f, 0x78, 0xe4, 0xad, 0x3b, 0x9, 0xc6, 0x19, 0x62, 0xc3, 0xe7, 0xf6, 0xbb, 0x34, 0x37, 0xaf, 0xd4, 0xd8, 0xa, 0x85, 0xf7, 0xf3, 0x1c, 0x70, 0x6f, 0x58, 0x31, 0x89, 0xd, 0xf8, 0xe8, 0x6, 0xbb, 0xc7, 0x3b, 0x6, 0x4f, 0xe, 0x8d, 0x83, 0xfd, 0x25, 0xa8, 0xaa, 0x3e, 0xb9, 0x7, 0x4b, 0x18, 0x48, 0x64, 0xda, 0xa5, 0xa7, 0xab, 0x96, 0x70, 0xc6, 0x95, 0xa6, 0x1c, 0xbb, 0x1a, 0x9b, 0x4f, 0xc5, 0xd3, 0x4e, 0xbd, 0x81, 0x59, 0xe, 0x55, 0x70, 0xb5, 0xa2, 0xa, 0x83, 0x74, 0x67, 0xe1, 0xdb, 0x7a, 0xa3, 0xc, 0x51, 0x75, 0xc7, 0x3d, 0x69, 0xe6, 0x1e, 0x21, 0x73, 0x66, 0x85, 0xb1, 0x47, 0x5d, 0x74, 0x94, 0x86, 0x2a, 0x3c, 0x12, 0x2a, 0x46, 0x2d, 0x4e, 0x80, 0xf7, 0xb8, 0x26, 0xe8, 0xd7, 0xda, 0x6f, 0x1d, 0xdb, 0x50, 0x1c, 0xf6, 0xfc, 0xbb, 0x4b, 0xfd, 0x54, 0xe, 0x47, 0x90, 0xb9, 0x36, 0x17, 0xe2, 0x78, 0xed, 0xd8, 0x93, 0x79, 0x24, 0x7f, 0x20, 0xe3, 0x4e, 0xd9, 0x3c, 0xd3, 0x12, 0xc7, 0xd, 0x96, 0x7a, 0x41, 0xd4, 0x91, 0xb4, 0xbe, 0x71, 0x95, 0xa, 0x16, 0x58, 0x41, 0x4f, 0x51, 0x8b, 0xf9, 0xde, 0x2, 0x7, 0xa9, 0x6c, 0xc2, 0xb0, 0x6, 0x2f, 0x39, 0xe, 0x1d, 0x63, 0xc3, 0xb7, 0xe0, 0xb4, 0x1a, 0xf, 0x8d, 0x12, 0x87, 0xab, 0xfc, 0xe9, 0x41, 0x7e, 0x87, 0xa5, 0xe4, 0xfb, 0x26, 0x2, 0xfd, 0xb7, 0x9b, 0x25, 0x44, 0x49, 0x75, 0x70, 0xb5, 0x4c, 0x58, 0x6f, 0xf6, 0xa, 0x4a, 0x48, 0xf3, 0x95, 0xaf, 0xa0, 0x90, 0x4, 0xe3, 0xaf, 0xa0, 0x38, 0xd9, 0xee, 0x7d, 0x5, 0x85, 0x22, 0xe2, 0x1f, 0x46, 0xa1, 0xf1, 0x90, 0x73, 0x1b, 0xdd, 0x90, 0xfd, 0x57, 0x50, 0xa8, 0x5c, 0x91, 0x57, 0x50, 0x9c, 0x2c, 0x77, 0xbd, 0x82, 0xe2, 0x52, 0x30, 0x8f, 0x5f, 0x38, 0xc9, 0x6f, 0xfc, 0xa, 0xa, 0x5a, 0xa4, 0x7e, 0x5, 0x25, 0x2c, 0x98, 0x78, 0x5, 0x5, 0xa7, 0x82, 0x1f, 0xcd, 0x40, 0x88, 0xde, 0xf1, 0xa, 0x8a, 0x43, 0xe5, 0x86, 0x57, 0x50, 0x92, 0xe, 0x31, 0xe8, 0x9d, 0xf8, 0xfa, 0x24, 0x86, 0xa, 0xb7, 0xc7, 0x83, 0xd5, 0xc2, 0x4e, 0x66, 0x21, 0x5c, 0x10, 0xf0, 0xa7, 0x23, 0xb, 0x6f, 0xae, 0x2, 0x2d, 0x75, 0x16, 0xce, 0xe3, 0xbb, 0x3a, 0x5b, 0xdf, 0x5, 0xd0, 0x4b, 0x59, 0xd9, 0x2b, 0xd6, 0xb1, 0xf0, 0x99, 0x6e, 0xb4, 0x48, 0x7f, 0x56, 0x10, 0x90, 0x4, 0x1b, 0xff, 0x9c, 0xbd, 0x61, 0xf8, 0x4c, 0xd5, 0x10, 0xb6, 0x19, 0xbf, 0x95, 0xa9, 0xa2, 0xd1, 0xc0, 0x71, 0x1c, 0x92, 0x6d, 0x8a, 0xe6, 0xfb, 0xda, 0xc0, 0x7c, 0xe1, 0x83, 0xc6, 0x4f, 0x70, 0xc, 0xc9, 0xe6, 0xc, 0xe, 0x36, 0x52, 0x8a, 0x74, 0xa4, 0xe9, 0x31, 0x24, 0x27, 0x15, 0xee, 0x9a, 0xda, 0xd5, 0xb3, 0x60, 0x24, 0xdf, 0x41, 0xe3, 0xc4, 0x2d, 0x5f, 0x4b, 0x14, 0x59, 0xe3, 0x91, 0x97, 0xcb, 0xc1, 0x8c, 0x1, 0xac, 0x19, 0x21, 0x8f, 0xe7, 0x38, 0xd9, 0xfe, 0xdb, 0x25, 0xe2, 0xea, 0xad, 0x55, 0x38, 0xe4, 0x59, 0x84, 0xae, 0x21, 0xed, 0x5d, 0xa, 0xde, 0xd4, 0xc8, 0x7b, 0x55, 0x2e, 0x86, 0xeb, 0x8d, 0xcd, 0x70, 0x9c, 0x4e, 0x5b, 0xb5, 0x5d, 0xd8, 0xd3, 0x83, 0x2c, 0xb2, 0x3c, 0xd1, 0xd6, 0xdd, 0xd8, 0xe7, 0xb4, 0xdc, 0x55, 0xf3, 0x24, 0x56, 0xa2, 0xb2, 0x2e, 0xae, 0xba, 0xd5, 0x9c, 0xa8, 0x49, 0x7, 0x92, 0x60, 0x58, 0xdb, 0x35, 0xfc, 0x45, 0x8c, 0x41, 0x18, 0x71, 0xa2, 0x1b, 0x5e, 0x97, 0x6a, 0x53, 0x47, 0x3e, 0x56, 0xab, 0xd5, 0x7d, 0x4d, 0xed, 0x9e, 0xbe, 0xba, 0x35, 0x5f, 0x82, 0x65, 0x85, 0x44, 0x1e, 0xb, 0x89, 0x8b, 0x31, 0x98, 0x2e, 0x23, 0x67, 0x40, 0xe2, 0xba, 0x17, 0x2c, 0x50, 0xfa, 0x8, 0xc2, 0xa1, 0xdd, 0x5c, 0x77, 0xd1, 0x12, 0xe0, 0x48, 0x4c, 0x2, 0xa7, 0x4b, 0xbb, 0xa6, 0xe, 0xd0, 0x8, 0x49, 0xb9, 0x61, 0x59, 0xd2, 0xe3, 0x4, 0xa4, 0xa4, 0xc8, 0xa4, 0xb1, 0x73, 0x77, 0xc6, 0x69, 0x74, 0xea, 0xe3, 0x89, 0xac, 0x69, 0x49, 0xa5, 0x8, 0x24, 0xad, 0x41, 0xe7, 0xe9, 0xef, 0x6d, 0x79, 0xdf, 0xca, 0x6e, 0x10, 0xf5, 0xeb, 0x66, 0x4c, 0x92, 0x99, 0xef, 0x96, 0xef, 0xdd, 0x66, 0x27, 0xac, 0xab, 0xd, 0x99, 0x48, 0x41, 0x28, 0x2e, 0xdd, 0x48, 0x82, 0x64, 0x2d, 0x70, 0xe2, 0x0, 0x88, 0x35, 0x16, 0xcd, 0x67, 0x18, 0x21, 0xb1, 0x3, 0x26, 0x1d, 0x31, 0x31, 0x51, 0xe9, 0x9b, 0xb2, 0xf8, 0x4d, 0x61, 0x2a, 0x51, 0xed, 0x19, 0xa0, 0x29, 0xef, 0x79, 0x7f, 0xc3, 0xa5, 0xd0, 0x69, 0xc0, 0x82, 0xe2, 0x7a, 0xc2, 0xc2, 0x71, 0xee, 0x1e, 0xb0, 0xf8, 0xe4, 0x82, 0x1, 0x8b, 0x8f, 0x10, 0x19, 0xb0, 0x60, 0xb4, 0x42, 0x63, 0x16, 0xc5, 0x4a, 0x54, 0x36, 0x36, 0x60, 0xa1, 0x6a, 0xd2, 0x81, 0xe4, 0xd, 0x86, 0x67, 0xf5, 0x71, 0x56, 0x8e, 0x1e, 0xe3, 0x55, 0x46, 0x6c, 0x4c, 0x2, 0xaf, 0x4b, 0xb5, 0xc9, 0x33, 0xaa, 0xfc, 0x9, 0x93, 0x7b, 0x9a, 0xba, 0xeb, 0x80, 0x5, 0xcf, 0x97, 0x60, 0x39, 0x31, 0x60, 0x49, 0x88, 0xf1, 0xf6, 0x1, 0x8b, 0x4f, 0x21, 0x18, 0xb0, 0xf8, 0x8, 0xe1, 0x80, 0xe5, 0x87, 0xe5, 0x66, 0x56, 0x8c, 0xe6, 0xf1, 0xb6, 0xf5, 0x6, 0x2b, 0x11, 0x9c, 0x2e, 0x6d, 0x9a, 0x18, 0xac, 0x48, 0x29, 0xdd, 0x3a, 0x58, 0x41, 0x4a, 0xa2, 0x9c, 0x91, 0x17, 0xf, 0xec, 0x66, 0x55, 0x88, 0x2c, 0xd7, 0xab, 0x73, 0xc9, 0xf7, 0x1a, 0xa1, 0x9b, 0x87, 0x57, 0xdd, 0x6b, 0xdd, 0xc5, 0x22, 0xdd, 0x36, 0xbc, 0xba, 0x83, 0x40, 0xd2, 0x76, 0x75, 0x1e, 0x5e, 0xdd, 0x96, 0xf7, 0xad, 0xac, 0x5c, 0xf7, 0xe1, 0xd5, 0x3d, 0x99, 0xef, 0x96, 0xef, 0xdd, 0x46, 0x32, 0xac, 0x6b, 0x30, 0xbc, 0xa, 0x20, 0x14, 0x97, 0xc4, 0xf0, 0xca, 0xaf, 0x5, 0x4e, 0xbc, 0xeb, 0xf0, 0x2a, 0x28, 0x8d, 0x1c, 0x5e, 0xc5, 0x30, 0x93, 0xc3, 0x2b, 0xaa, 0xd2, 0x37, 0x65, 0xf1, 0x9b, 0xe2, 0x3a, 0x5c, 0x9e, 0x98, 0xc5, 0x59, 0x9d, 0xce, 0xbb, 0xa5, 0x7b, 0x2b, 0x72, 0x86, 0x9e, 0x6e, 0xb, 0x62, 0xa4, 0x76, 0xd, 0x82, 0xa, 0xb, 0x82, 0xc7, 0x40, 0xdd, 0xed, 0xc, 0x7, 0xe7, 0xa1, 0xae, 0xf2, 0x65, 0xc9, 0xbc, 0x3, 0xf, 0xc9, 0xae, 0x82, 0xfe, 0x7d, 0xf8, 0x5b, 0x96, 0x15, 0xd9, 0x3b, 0xb3, 0xc5, 0x25, 0xa2, 0xf4, 0x78, 0x66, 0x19, 0x52, 0xd1, 0x67, 0x7, 0x3d, 0x8c, 0x63, 0xc1, 0xea, 0x25, 0x4e, 0x14, 0xe0, 0x4b, 0xfa, 0xde, 0xc1, 0x26, 0xb5, 0xc5, 0x36, 0x16, 0xdb, 0x4f, 0x61, 0xcd, 0x2c, 0xb5, 0xb0, 0x66, 0x1e, 0x94, 0xf7, 0x46, 0x37, 0x81, 0xa9, 0x7d, 0x3c, 0xb6, 0x5e, 0xf8, 0xba, 0x31, 0x71, 0x11, 0xe3, 0xbe, 0xa8, 0xa7, 0x1d, 0xee, 0xa9, 0x86, 0x97, 0x99, 0x9c, 0x2a, 0x38, 0xb7, 0xab, 0xfc, 0xfa, 0x39, 0x40, 0x51, 0x57, 0x77, 0x5d, 0xfd, 0xbe, 0x2b, 0x72, 0x6e, 0x11, 0xe0, 0xa, 0x56, 0x50, 0x3c, 0x80, 0x89, 0xd2, 0xef, 0xbd, 0x28, 0xe9, 0xb5, 0xa2, 0xee, 0xd8, 0x7e, 0xb2, 0xb2, 0x33, 0x61, 0x13, 0xe3, 0x19, 0x4, 0xe4, 0x96, 0x79, 0x76, 0x64, 0x96, 0x3, 0x28, 0x3, 0xc7, 0x8a, 0xa5, 0x22, 0xbc, 0x4, 0xee, 0x10, 0x81, 0x71, 0x66, 0x49, 0x40, 0x84, 0x26, 0xa8, 0xa4, 0x8d, 0xfb, 0x91, 0xaa, 0x6e, 0x62, 0x52, 0x17, 0x5c, 0xae, 0x81, 0xe5, 0x42, 0xd7, 0x87, 0xa7, 0x63, 0xdc, 0xfa, 0xe, 0x8b, 0x80, 0x86, 0x52, 0x70, 0x40, 0x51, 0xca, 0x61, 0x73, 0x4f, 0xc6, 0x93, 0xd5, 0x74, 0x7e, 0xfb, 0xd3, 0xce, 0xe8, 0xb5, 0x36, 0x5b, 0x26, 0x8f, 0x71, 0xe1, 0x1b, 0x1b, 0x95, 0x26, 0xed, 0x4d, 0xe2, 0x6, 0x78, 0x48, 0x8b, 0xee, 0xe4, 0x8, 0x1c, 0xe9, 0x69, 0xb7, 0xf7, 0x6c, 0x45, 0x97, 0xea, 0xdc, 0x21, 0xf8, 0x8d, 0xfa, 0x37, 0xf, 0xda, 0x10, 0xc8, 0x4e, 0xa6, 0x39, 0xb2, 0x23, 0x6e, 0xe2, 0x87, 0xa4, 0x22, 0xa2, 0xb, 0xe1, 0x6f, 0x23, 0x3a, 0x49, 0x97, 0x14, 0x5d, 0x0, 0x7e, 0xad, 0xe8, 0x98, 0x42, 0x47, 0x5d, 0xa6, 0x3f, 0x6a, 0x8, 0xae, 0xa3, 0x28, 0x2a, 0x3d, 0xdc, 0x7f, 0xa, 0x80, 0xaa, 0x83, 0xfc, 0x16, 0xc, 0xc7, 0x5c, 0xb7, 0x6c, 0x9e, 0x29, 0x76, 0x50, 0xee, 0x8e, 0xd8, 0xc, 0x72, 0x9b, 0xcd, 0x72, 0x2, 0x7a, 0xb9, 0x4e, 0xb9, 0xed, 0xba, 0xac, 0x5a, 0x34, 0x95, 0xf9, 0x87, 0x7b, 0x96, 0xcb, 0x56, 0x4f, 0xfe, 0x14, 0x35, 0x4, 0x5b, 0x80, 0x6, 0xf9, 0x78, 0x2a, 0x3f, 0x57, 0x87, 0x73, 0x3, 0x32, 0x98, 0x24, 0x90, 0x49, 0x9e, 0x30, 0x52, 0x8, 0x9e, 0x45, 0x74, 0x93, 0xdc, 0xca, 0xe0, 0x76, 0xd0, 0x1, 0x88, 0x52, 0x3a, 0x1a, 0x30, 0xcc, 0x4e, 0xc9, 0xc3, 0xc, 0x6e, 0xeb, 0x99, 0x76, 0x1b, 0x8e, 0xcb, 0x5d, 0x6f, 0x38, 0xe7, 0x7f, 0x4d, 0xca, 0x1d, 0xe8, 0x5c, 0x8f, 0xb3, 0x1f, 0xbd, 0x38, 0x1c, 0x7e, 0x4c, 0x75, 0xe7, 0x7e, 0x53, 0x3a, 0x3c, 0xc8, 0xb2, 0x68, 0x4a, 0xf9, 0xac, 0x8c, 0xd3, 0xd6, 0xc3, 0xf1, 0xac, 0xdc, 0x5d, 0xb, 0xc9, 0xa5, 0x92, 0x8d, 0xfe, 0xd5, 0x2d, 0x96, 0xbb, 0xaa, 0xb3, 0x8a, 0xd7, 0xa5, 0xea, 0x9b, 0x97, 0xbb, 0x63, 0xfb, 0xcd, 0xbb, 0xe6, 0x22, 0xe2, 0x58, 0xaa, 0xb3, 0x1d, 0xc1, 0x10, 0x50, 0xdf, 0x60, 0x51, 0x4, 0x92, 0x5b, 0xb6, 0x1e, 0xde, 0x2f, 0xdb, 0x53, 0xb9, 0x31, 0x33, 0x10, 0xc, 0x44, 0x2d, 0x76, 0x4c, 0x9e, 0xd8, 0xcc, 0xa0, 0xd4, 0xe4, 0x90, 0xc7, 0xb3, 0xbd, 0x1b, 0x6f, 0xe, 0x1e, 0x56, 0xac, 0xb, 0xa2, 0x8a, 0x95, 0xf, 0x81, 0x6b, 0x72, 0xc8, 0x7b, 0xbd, 0xce, 0x83, 0xa9, 0x1e, 0x1e, 0x56, 0xac, 0xb, 0x22, 0xf7, 0xa1, 0xc4, 0xdb, 0xc3, 0x9a, 0x9c, 0xff, 0x7a, 0xa8, 0xf3, 0xee, 0x23, 0x44, 0xc2, 0xa, 0x4, 0xe9, 0xa4, 0x6c, 0xc5, 0xd3, 0xa7, 0x9a, 0x10, 0xf2, 0xc6, 0xa1, 0xf3, 0xc8, 0x9c, 0x87, 0x87, 0x95, 0xe9, 0x82, 0xa8, 0x62, 0xe5, 0x7b, 0x8d, 0x46, 0x43, 0x82, 0xf7, 0xd5, 0x9c, 0x37, 0xaf, 0x5c, 0x34, 0x54, 0x8f, 0x20, 0x84, 0x5c, 0x33, 0x13, 0xcf, 0xc4, 0x5d, 0xd5, 0xab, 0x5a, 0xf8, 0xd1, 0x29, 0xfb, 0x1e, 0x7, 0x7c, 0x8e, 0x83, 0xc7, 0xbd, 0x7f, 0xc, 0x63, 0xdc, 0xc0, 0xa8, 0x3c, 0x93, 0x2c, 0xf3, 0xc6, 0x90, 0xae, 0x6d, 0xa0, 0xfa, 0x3a, 0x62, 0x16, 0x6e, 0xe, 0xe7, 0x63, 0xbc, 0x82, 0x38, 0xc9, 0x2e, 0xaa, 0x47, 0xf7, 0x6e, 0x59, 0xfb, 0x58, 0xef, 0xe, 0x5e, 0x57, 0x52, 0x99, 0xf4, 0x23, 0x4b, 0x9a, 0x86, 0x73, 0xd6, 0x48, 0xbf, 0xb8, 0xc4, 0xc, 0x95, 0x64, 0x40, 0x1b, 0x2a, 0xf9, 0xeb, 0x4e, 0x43, 0xc5, 0xdd, 0xb4, 0x64, 0x85, 0x49, 0x69, 0xa7, 0x7, 0xf0, 0x9a, 0x1d, 0x7b, 0x35, 0xd6, 0x4c, 0x17, 0x9e, 0x6f, 0x79, 0xcf, 0xdc, 0x23, 0xaf, 0xf3, 0x3a, 0x4e, 0xe, 0xc7, 0x79, 0x50, 0xa8, 0xce, 0x69, 0x96, 0x99, 0x7f, 0xc5, 0xd7, 0xb2, 0x3, 0xe7, 0x98, 0x62, 0x4c, 0xf6, 0xf7, 0xf3, 0x8e, 0x8d, 0x6b, 0x4e, 0x20, 0xf4, 0xd3, 0x24, 0xc3, 0x57, 0x39, 0x26, 0x99, 0x59, 0x50, 0xa8, 0xf6, 0xdb, 0xf2, 0x54, 0xb5, 0x91, 0x70, 0x17, 0x86, 0x6c, 0x6f, 0xb8, 0x1d, 0xf5, 0xc1, 0xcf, 0xed, 0xe8, 0xe2, 0xd0, 0x80, 0xa8, 0xfe, 0xd9, 0x36, 0xef, 0xf2, 0xc4, 0xd8, 0x57, 0xf5, 0x71, 0x96, 0x81, 0xec, 0xcf, 0xdb, 0x13, 0x8c, 0x2a, 0xea, 0x99, 0x6c, 0x70, 0xb1, 0xc1, 0xe4, 0xe8, 0x87, 0xb7, 0x19, 0xac, 0x38, 0x82, 0xc5, 0xc, 0x50, 0x25, 0x93, 0xed, 0xe2, 0x85, 0x20, 0x56, 0xb, 0xdf, 0xcd, 0xea, 0x54, 0x96, 0x7b, 0x79, 0xd7, 0x2a, 0x3c, 0xed, 0x14, 0x8a, 0x7c, 0xfa, 0x51, 0x46, 0x5f, 0xbe, 0x99, 0x49, 0x67, 0x6c, 0x9, 0x1f, 0xee, 0x51, 0x9a, 0x30, 0xcf, 0x9c, 0x36, 0x46, 0x1a, 0xc3, 0x8a, 0x77, 0xfe, 0xa8, 0xce, 0x50, 0xb7, 0x5b, 0x86, 0xb0, 0x2f, 0xaa, 0x9a, 0x78, 0x7c, 0x63, 0x4a, 0x2d, 0x80, 0x45, 0xa2, 0x60, 0x84, 0x6f, 0xfe, 0x80, 0xe7, 0xbd, 0x24, 0x4a, 0x6f, 0x38, 0x6e, 0x7a, 0xfc, 0x55, 0x27, 0xe6, 0x2d, 0x6, 0x87, 0x73, 0xeb, 0x3d, 0x11, 0x46, 0x20, 0x25, 0x31, 0x40, 0x7d, 0x7a, 0x22, 0x6c, 0x48, 0xdf, 0x26, 0xa8, 0x28, 0x22, 0xb6, 0x4b, 0xc0, 0x3b, 0x4, 0xe0, 0x9d, 0x89, 0xc2, 0x66, 0xd1, 0x4f, 0x28, 0x80, 0x24, 0x63, 0x61, 0x6c, 0xa, 0x16, 0xbe, 0x43, 0xf, 0xa, 0x2c, 0x3b, 0xc3, 0x55, 0x71, 0x14, 0x4b, 0x6d, 0xe0, 0x92, 0x8b, 0xbf, 0x64, 0x57, 0xd4, 0xcc, 0x5e, 0xdb, 0x69, 0x29, 0xb1, 0xf8, 0x78, 0xdb, 0x5, 0x16, 0x41, 0xb3, 0xb7, 0x9d, 0xba, 0xc7, 0x28, 0xbd, 0x6e, 0x29, 0x91, 0xe4, 0x3f, 0x32, 0x8, 0x39, 0xec, 0x7a, 0x8f, 0x99, 0xa6, 0xf3, 0x7c, 0xec, 0xab, 0x8f, 0x73, 0x70, 0xae, 0xd8, 0xa0, 0x3c, 0x1c, 0xfd, 0x77, 0xe9, 0x14, 0x61, 0xa6, 0x61, 0xbb, 0xaa, 0x11, 0xc3, 0xe7, 0xbe, 0x9b, 0xc4, 0x2f, 0x6d, 0x5e, 0x5c, 0x6d, 0x9e, 0xe0, 0x19, 0x99, 0x1c, 0xeb, 0x43, 0x83, 0xe5, 0x57, 0x10, 0xca, 0xc9, 0xf0, 0x1b, 0x37, 0xea, 0xb8, 0xa0, 0x90, 0x22, 0x26, 0x81, 0xe4, 0x70, 0x2b, 0xb2, 0x12, 0x81, 0xb4, 0xa4, 0x79, 0xea, 0x1e, 0x33, 0x56, 0xce, 0xaa, 0x95, 0x8b, 0xe, 0xdb, 0x41, 0xeb, 0xd3, 0x98, 0xff, 0xd1, 0x88, 0xd1, 0xe1, 0xd9, 0x8d, 0x3c, 0x8a, 0xe7, 0xbd, 0x3b, 0x32, 0x28, 0x9f, 0x2, 0x4f, 0x71, 0x97, 0x1a, 0xce, 0xdd, 0xc8, 0xa0, 0x7e, 0x7e, 0xb8, 0x23, 0x8f, 0xe6, 0xb5, 0xe2, 0x14, 0x9b, 0x89, 0xe1, 0xdf, 0x8d, 0x5c, 0xaa, 0xc7, 0x53, 0x3b, 0x32, 0xa9, 0x9f, 0x5a, 0x25, 0x79, 0xfc, 0xb3, 0xb6, 0x9c, 0xbf, 0x96, 0xdf, 0x36, 0xa7, 0x62, 0x57, 0x36, 0x3d, 0xfe, 0xf8, 0xd3, 0x89, 0xa9, 0xc7, 0x40, 0x5e, 0xe0, 0x3c, 0x55, 0xc7, 0xb2, 0xb9, 0x6c, 0x4e, 0xfc, 0x32, 0xa3, 0xad, 0x82, 0x51, 0x7e, 0x7e, 0xbf, 0x90, 0x79, 0x99, 0xf6, 0x80, 0x42, 0xf9, 0xa5, 0x46, 0x56, 0xc6, 0xe1, 0xbb, 0x92, 0xff, 0x8e, 0xb4, 0x87, 0x9a, 0xe2, 0xc5, 0x8f, 0x26, 0x5, 0xaf, 0x5a, 0x62, 0xb6, 0xf3, 0xe6, 0xd7, 0xea, 0xf0, 0xbb, 0x39, 0x7c, 0xc5, 0x50, 0x5c, 0xc0, 0x91, 0x71, 0xa9, 0x23, 0xb7, 0x78, 0x42, 0x4c, 0xcb, 0xbd, 0x38, 0x4a, 0x10, 0xc4, 0x7e, 0x36, 0xaf, 0x18, 0x8a, 0x68, 0x48, 0x91, 0xf0, 0xb7, 0xc0, 0x8e, 0x11, 0xd3, 0x7f, 0x72, 0x45, 0x39, 0x52, 0xbd, 0x1, 0xb8, 0x5e, 0xa4, 0x79, 0x9e, 0xa1, 0xd5, 0x23, 0x30, 0x11, 0xa7, 0x2f, 0x2a, 0xd6, 0x1b, 0xce, 0xa5, 0xb3, 0xf6, 0x9c, 0xbd, 0x7, 0x24, 0x21, 0xae, 0xdc, 0x94, 0x1e, 0xad, 0xfb, 0x36, 0x55, 0xa5, 0xf4, 0x5c, 0xf9, 0x6, 0x37, 0xd9, 0x34, 0x7f, 0xf2, 0x6d, 0xd1, 0x81, 0x79, 0x32, 0x6d, 0x3a, 0x5b, 0x97, 0x2f, 0x7d, 0xe4, 0x5a, 0xd5, 0xec, 0x7d, 0x6f, 0x3c, 0xfb, 0xb1, 0xf, 0xfa, 0x71, 0xf0, 0x7b, 0x96, 0xfd, 0x48, 0xe4, 0xa4, 0x21, 0x8f, 0x1e, 0xd, 0xef, 0xf7, 0xfb, 0xf0, 0xfe, 0x2a, 0x93, 0xdb, 0xff, 0x7f, 0x4c, 0xff, 0xcb, 0x73, 0x8c, 0x3c, 0x4c, 0x29, 0xfa, 0x9b, 0xb0, 0x43, 0x22, 0xbe, 0x9, 0x9, 0x71, 0x55, 0xd2, 0xbc, 0xb8, 0xa5, 0x13, 0x55, 0x82, 0xa7, 0x90, 0xba, 0xbc, 0x62, 0xcf, 0x4, 0x24, 0xf4, 0x1c, 0xb3, 0x8f, 0xbd, 0xb1, 0x7e, 0xfd, 0xb6, 0xc7, 0xdc, 0x6e, 0xb5, 0x67, 0xf3, 0x40, 0xde, 0x6f, 0x6e, 0xcf, 0x74, 0x73, 0xe, 0xbf, 0x9f, 0x25, 0x97, 0xa0, 0xe2, 0x1d, 0x10, 0x23, 0xf0, 0x7b, 0x47, 0xfc, 0xbd, 0x23, 0x6, 0x1c, 0x7b, 0x7a, 0x97, 0x58, 0x83, 0x4c, 0x28, 0x9d, 0x9f, 0xfb, 0x77, 0x8d, 0xfb, 0x5d, 0xe3, 0x52, 0x1a, 0x97, 0x5e, 0x87, 0x4e, 0x28, 0x1d, 0x42, 0xe0, 0x77, 0xbd, 0xfb, 0x5d, 0xef, 0x52, 0x7a, 0x97, 0xdc, 0x88, 0x48, 0xa8, 0x5d, 0x98, 0xff, 0x77, 0xad, 0xfb, 0x5d, 0xeb, 0x10, 0xad, 0x13, 0xb, 0xd6, 0x70, 0x71, 0x4e, 0xee, 0xe8, 0x8b, 0x64, 0xec, 0x15, 0x51, 0xf5, 0x3a, 0x81, 0x80, 0xf7, 0xe5, 0x3f, 0x6c, 0xc6, 0xb8, 0xfe, 0x76, 0xf9, 0xed, 0xc0, 0x57, 0xec, 0xfd, 0x50, 0xce, 0x57, 0x88, 0x62, 0x16, 0xca, 0x45, 0x4c, 0x30, 0x5, 0x39, 0x2c, 0xff, 0x5e, 0xae, 0x5a, 0x3f, 0x86, 0xa1, 0x84, 0x89, 0xc5, 0x39, 0x55, 0xca, 0x33, 0x7c, 0xde, 0xdd, 0x8d, 0xd6, 0x7, 0xa8, 0xf1, 0x4, 0x37, 0x83, 0xb8, 0x54, 0xec, 0x5, 0xfc, 0x3, 0x19, 0x38, 0x63, 0xfd, 0x30, 0xb3, 0x2a, 0x7, 0x89, 0xc9, 0xe9, 0xed, 0x9f, 0x31, 0x79, 0x68, 0x52, 0x32, 0x84, 0xc1, 0x85, 0x8, 0x6c, 0xa0, 0x8b, 0x13, 0xb1, 0xa6, 0xfc, 0x4d, 0x38, 0x91, 0xaa, 0x71, 0xf8, 0x49, 0x77, 0xee, 0x32, 0x22, 0xe1, 0x13, 0x66, 0xa0, 0xc6, 0x55, 0xd3, 0x5e, 0x52, 0xf1, 0xd2, 0xed, 0xe6, 0x91, 0xb7, 0x44, 0x3b, 0xce, 0xfc, 0xd8, 0x87, 0x59, 0xb0, 0xd5, 0x74, 0x7b, 0xf0, 0x74, 0x24, 0x88, 0xf6, 0x7d, 0xa7, 0x4d, 0x2, 0x5e, 0x5e, 0xfd, 0x86, 0x9c, 0x4f, 0x8f, 0xe, 0x91, 0x70, 0xff, 0xb3, 0x86, 0x85, 0x5f, 0x4a, 0x3f, 0x48, 0xe9, 0xf9, 0x9, 0xa6, 0xd5, 0xdd, 0xa5, 0xc4, 0x22, 0x14, 0x80, 0x3e, 0x77, 0xe1, 0xa5, 0x47, 0x8e, 0xd9, 0x74, 0xbd, 0xa9, 0xe8, 0xef, 0x72, 0xea, 0x73, 0x2d, 0x7d, 0x12, 0x62, 0x36, 0xbf, 0x29, 0x38, 0xb9, 0xed, 0x2e, 0x79, 0xe9, 0x70, 0x24, 0x86, 0xa0, 0x4c, 0xa, 0x30, 0xc5, 0xec, 0x3d, 0x19, 0x45, 0x2d, 0x52, 0x4d, 0x66, 0xf6, 0xd, 0xba, 0xb3, 0xcc, 0x5b, 0xeb, 0x76, 0x7e, 0x13, 0xb9, 0x8, 0x66, 0xe1, 0xa5, 0x38, 0x73, 0x2c, 0x6, 0xdd, 0xd6, 0xee, 0x13, 0xe9, 0x54, 0x63, 0x2b, 0x28, 0x71, 0x90, 0x35, 0x16, 0x13, 0x7a, 0x81, 0xef, 0x90, 0xe1, 0x5, 0xdc, 0xd0, 0x70, 0x89, 0xc, 0xcf, 0xc3, 0x66, 0xc7, 0x14, 0xec, 0xf6, 0x7c, 0xd1, 0x6c, 0x37, 0xab, 0x57, 0xa7, 0x6c, 0x9, 0x5e, 0x53, 0xb9, 0xe3, 0x99, 0xe3, 0x7a, 0x7d, 0x67, 0xb6, 0x14, 0xc7, 0x89, 0xdc, 0x22, 0x73, 0xaa, 0x4b, 0x51, 0xd, 0x85, 0x77, 0x8d, 0xb8, 0xa8, 0xa2, 0x79, 0x3a, 0x74, 0xa6, 0xcd, 0x13, 0xb3, 0xb7, 0x61, 0x67, 0x32, 0x6b, 0x5c, 0x29, 0xeb, 0xab, 0x96, 0xcc, 0x8a, 0x6e, 0x4, 0x68, 0xbc, 0xae, 0xf6, 0x89, 0x24, 0x40, 0xb9, 0x16, 0x3, 0xef, 0x78, 0x1e, 0x7f, 0x55, 0x94, 0xd3, 0x48, 0x7d, 0xec, 0xe, 0x7a, 0x1c, 0x21, 0xc5, 0x8e, 0x6b, 0x77, 0xa0, 0xb5, 0x71, 0x8c, 0x8a, 0xde, 0x93, 0xf3, 0xa9, 0x88, 0xd5, 0xa0, 0x64, 0xdb, 0xc8, 0x95, 0xa5, 0xa2, 0x43, 0x6e, 0x2, 0xe9, 0xfe, 0x56, 0xe1, 0xb9, 0x49, 0x19, 0x8, 0x60, 0xc7, 0xf6, 0x98, 0x2f, 0x3f, 0xae, 0xb, 0xa2, 0x0, 0xba, 0x31, 0x0, 0x34, 0xca, 0x5, 0xdd, 0xc, 0x94, 0xd3, 0xef, 0xd6, 0x3e, 0x7a, 0xe1, 0x24, 0x55, 0x3d, 0xb5, 0xe, 0x53, 0x74, 0x23, 0x40, 0xe3, 0xdd, 0xdf, 0x50, 0x8a, 0x0, 0x29, 0x25, 0xd, 0xef, 0xd6, 0x5c, 0x65, 0x59, 0x8c, 0x27, 0x73, 0xba, 0x18, 0xba, 0xc5, 0x5c, 0x84, 0x14, 0x3b, 0xaf, 0xec, 0x3e, 0x6a, 0x81, 0x21, 0x79, 0x5b, 0x45, 0x2e, 0x57, 0x14, 0x9d, 0xf2, 0x93, 0x68, 0xf7, 0xb7, 0x8d, 0xcc, 0x4f, 0xca, 0x42, 0x81, 0xbb, 0xb5, 0xcc, 0x7a, 0x3a, 0xd9, 0x4c, 0xa, 0xb2, 0x10, 0xba, 0x61, 0x1c, 0x78, 0x82, 0x97, 0x57, 0x36, 0x4b, 0xd7, 0xb9, 0x23, 0xea, 0xd0, 0xfc, 0x9, 0x90, 0xf7, 0x90, 0x2f, 0x3f, 0x34, 0xbf, 0xf, 0x82, 0x7, 0xbe, 0x7a, 0xf, 0x5d, 0xee, 0x89, 0x8f, 0xbc, 0x3d, 0xf1, 0xcc, 0xdd, 0x5f, 0x26, 0x91, 0x14, 0x53, 0x72, 0x81, 0x1, 0x1e, 0x93, 0xd2, 0x0, 0x2d, 0x11, 0x32, 0xf6, 0x67, 0x34, 0xb4, 0x27, 0x35, 0xc5, 0x1c, 0x8c, 0xa8, 0x39, 0xe6, 0x60, 0xe4, 0x95, 0x8c, 0xbe, 0x17, 0xa2, 0x2, 0x1b, 0x78, 0xc3, 0x1c, 0x99, 0xaf, 0xad, 0xda, 0xba, 0xbc, 0x44, 0x83, 0x27, 0x82, 0x13, 0x0, 0x8f, 0xe1, 0xc1, 0x25, 0x40, 0xc6, 0xc, 0xc6, 0xc2, 0x34, 0x79, 0xe5, 0xc1, 0xa6, 0x7a, 0x3f, 0x91, 0x7c, 0x2a, 0x1b, 0xce, 0xf5, 0xe6, 0x70, 0x68, 0xed, 0x6d, 0x17, 0x28, 0xe6, 0xc4, 0x8d, 0xbd, 0x8e, 0xb1, 0x57, 0x29, 0xf9, 0x23, 0x33, 0x70, 0xd3, 0x4, 0xcf, 0x40, 0xcf, 0xfb, 0x3a, 0x49, 0xb2, 0xab, 0x83, 0x2f, 0x3c, 0xd3, 0x6b, 0x23, 0x19, 0x42, 0x25, 0xb0, 0x44, 0x1d, 0xc8, 0x6, 0x79, 0x2e, 0x61, 0x44, 0x71, 0xec, 0xee, 0xac, 0x57, 0x34, 0x5c, 0xfa, 0xe8, 0xc5, 0xd6, 0x45, 0x3a, 0xb0, 0xd4, 0x99, 0xd6, 0xc5, 0x79, 0x6, 0xe2, 0x15, 0xbd, 0xc1, 0x29, 0xdd, 0x2e, 0xba, 0xf4, 0x22, 0xb, 0x32, 0x5d, 0xea, 0xd1, 0x8d, 0x92, 0xff, 0xc, 0xce, 0xab, 0x34, 0xcb, 0x16, 0xf3, 0xe0, 0xa8, 0x7e, 0xdf, 0xed, 0xf6, 0xf, 0x31, 0xd, 0xa0, 0x96, 0xb1, 0xd4, 0x69, 0x9f, 0x2b, 0x55, 0xf3, 0x56, 0x1e, 0x94, 0x54, 0x50, 0xe4, 0xd7, 0xe0, 0x54, 0x36, 0xc7, 0xc3, 0xbe, 0x11, 0xa7, 0xd3, 0x45, 0xa, 0xa9, 0xd4, 0x28, 0xed, 0x9e, 0x3a, 0x92, 0xea, 0x52, 0xc5, 0x53, 0xc3, 0xb2, 0x7a, 0xde, 0x81, 0x56, 0x10, 0xf, 0x32, 0x7c, 0x72, 0xe5, 0x4a, 0x11, 0x73, 0x1f, 0xa5, 0x14, 0x50, 0x54, 0xbd, 0x3, 0xc8, 0xe5, 0x55, 0xfa, 0x79, 0x23, 0x1b, 0xcf, 0x2d, 0x77, 0x39, 0x6e, 0xca, 0x89, 0xe6, 0xf3, 0x16, 0xc2, 0x5c, 0x83, 0x3a, 0x13, 0x7e, 0x5, 0x4f, 0x37, 0x95, 0x7a, 0x21, 0x25, 0x18, 0x31, 0xb, 0xdf, 0x4d, 0xb8, 0xbd, 0x76, 0xfd, 0x36, 0xb2, 0x4e, 0x96, 0xb3, 0xfd, 0x87, 0xb4, 0xe9, 0x9b, 0xd5, 0x27, 0x59, 0xce, 0xf6, 0x8d, 0x54, 0x29, 0xca, 0xf1, 0xdb, 0xc9, 0xf8, 0xed, 0xa4, 0xf8, 0x1a, 0x39, 0x5d, 0xfe, 0xf1, 0xe6, 0x83, 0xd7, 0x5, 0xf1, 0x85, 0xdf, 0x43, 0xc1, 0xdf, 0xa2, 0x98, 0xe, 0x2d, 0xf3, 0xf, 0x29, 0x86, 0xae, 0xcd, 0x9b, 0x49, 0xff, 0xcd, 0xe4, 0xfb, 0x66, 0x12, 0x7c, 0x85, 0x8c, 0x2e, 0xf7, 0x18, 0x6f, 0xf8, 0xb4, 0xb3, 0x64, 0x80, 0xe4, 0x8c, 0x1a, 0x84, 0xdd, 0x37, 0x9c, 0xbf, 0x89, 0x13, 0xd5, 0x36, 0x30, 0xe1, 0xd4, 0x49, 0x9, 0xe3, 0x44, 0xf9, 0x68, 0xaf, 0x23, 0xd1, 0x7b, 0x99, 0xe9, 0x5e, 0xde, 0x25, 0x26, 0xb6, 0xf8, 0x30, 0xf7, 0xbb, 0x8, 0xb5, 0xb3, 0x1f, 0x7b, 0x55, 0x19, 0xdb, 0xb7, 0x28, 0x23, 0x2a, 0xd7, 0x37, 0xaa, 0x47, 0xa2, 0x8c, 0x98, 0xdf, 0x7b, 0x1b, 0x91, 0xbf, 0x91, 0x54, 0xdf, 0x48, 0x70, 0x77, 0xcb, 0xe6, 0xf2, 0xf, 0xb7, 0xe, 0x5d, 0x1d, 0xd6, 0x2b, 0xf5, 0xf8, 0x3b, 0x9b, 0xa3, 0xb7, 0xa9, 0x45, 0xb2, 0xa5, 0x5e, 0x6f, 0xff, 0xa2, 0xde, 0xed, 0x4d, 0x24, 0xfa, 0x36, 0x42, 0xbb, 0x57, 0x2e, 0x97, 0x6e, 0xa6, 0xd8, 0xae, 0x65, 0x3e, 0x78, 0xb3, 0xfb, 0x0, 0x2, 0x9a, 0xcf, 0x65, 0xf1, 0x1, 0xe0, 0x92, 0x2d, 0xe, 0x91, 0x2e, 0xe8, 0x42, 0x9c, 0x39, 0x24, 0x0, 0x29, 0x74, 0x19, 0x37, 0xf5, 0x6f, 0xcd, 0xb1, 0x75, 0x16, 0x99, 0xbc, 0xde, 0x2c, 0x41, 0xe5, 0x3a, 0xb5, 0xf4, 0x60, 0x10, 0xf5, 0x23, 0xc2, 0x14, 0x21, 0xc9, 0x10, 0x63, 0xe2, 0x39, 0x6a, 0xe2, 0x11, 0xf4, 0x6d, 0x27, 0x74, 0xae, 0x14, 0x37, 0x50, 0x37, 0xe8, 0xdd, 0xa8, 0xf3, 0xb1, 0xdd, 0xd, 0xd4, 0xd, 0x7a, 0x37, 0x8f, 0x79, 0xa7, 0xac, 0x3a, 0x11, 0xb8, 0x97, 0x83, 0x4e, 0xf2, 0xec, 0x44, 0xe0, 0x5e, 0xe, 0x3a, 0xc9, 0xbc, 0x13, 0x1, 0xd4, 0xa7, 0xe9, 0x53, 0x77, 0x69, 0x6d, 0x25, 0x2d, 0x39, 0x2a, 0xee, 0xe, 0xd8, 0x40, 0xb6, 0xb7, 0x60, 0x77, 0xa2, 0xd, 0xa4, 0x76, 0xb, 0x76, 0x27, 0x97, 0x78, 0x9f, 0x94, 0x3a, 0xaa, 0xe9, 0x5d, 0xf9, 0xbb, 0x48, 0xb2, 0xa3, 0x92, 0xde, 0x95, 0xbf, 0x8b, 0xb4, 0x3b, 0xaa, 0x68, 0xe8, 0xb4, 0xf4, 0x1b, 0x39, 0x9, 0xa5, 0x73, 0x8d, 0x7c, 0x52, 0x47, 0xbd, 0x49, 0x6b, 0x12, 0x1d, 0x3a, 0xda, 0xf5, 0x4d, 0xd8, 0xdb, 0x94, 0x4a, 0x77, 0xa4, 0x8d, 0x61, 0x6f, 0x53, 0x2a, 0xdd, 0x55, 0x2a, 0x28, 0xfa, 0xf6, 0x76, 0x15, 0x8e, 0x97, 0x77, 0x33, 0x81, 0x7b, 0x38, 0x88, 0x49, 0xf3, 0xd6, 0xfc, 0xdb, 0xdb, 0x3b, 0xd1, 0xdd, 0xe5, 0x77, 0x69, 0xdf, 0xe, 0x9d, 0xe8, 0xfe, 0x16, 0xc0, 0x75, 0xc0, 0xdf, 0xbd, 0x22, 0xe7, 0x3b, 0x17, 0xff, 0x89, 0x36, 0x2f, 0x7, 0x7e, 0x2, 0x7c, 0x64, 0xf7, 0xca, 0xd5, 0x66, 0x15, 0xb6, 0xcd, 0x4f, 0xed, 0x50, 0x3a, 0x79, 0x1e, 0xdc, 0xac, 0x26, 0xd6, 0x47, 0x88, 0x69, 0xb6, 0xe5, 0xf1, 0xba, 0xa1, 0xb8, 0xf, 0x91, 0x8d, 0xc0, 0xfe, 0x4d, 0xf9, 0x52, 0x63, 0x5f, 0x2f, 0x7c, 0x6c, 0x40, 0x58, 0xed, 0x75, 0x23, 0xc3, 0x56, 0xc, 0xcf, 0x2f, 0xbf, 0x87, 0x94, 0x1f, 0x3b, 0x84, 0xa0, 0x49, 0xab, 0x18, 0x75, 0x7d, 0xf7, 0xe7, 0x33, 0x2e, 0x50, 0x34, 0xe, 0x2e, 0x9d, 0xad, 0xa3, 0x8c, 0x6e, 0x25, 0xdb, 0x73, 0xa3, 0x60, 0x6d, 0x66, 0xfc, 0xf, 0x72, 0x22, 0x60, 0x32, 0x99, 0x10, 0x84, 0x70, 0x11, 0x3e, 0x93, 0x22, 0xa4, 0x39, 0x34, 0xe1, 0xfa, 0x12, 0x2, 0x52, 0x78, 0xbe, 0x5c, 0x6f, 0x3e, 0xce, 0xdc, 0x99, 0xf4, 0xab, 0x65, 0x8f, 0x93, 0xed, 0xdd, 0x12, 0x81, 0xc, 0x25, 0xf4, 0x76, 0xb2, 0x37, 0xf7, 0xbd, 0x13, 0x2, 0x52, 0x78, 0x84, 0xec, 0x13, 0x47, 0x68, 0x17, 0xf7, 0x51, 0x7f, 0xb5, 0xf8, 0x71, 0xb2, 0x9e, 0xf8, 0x35, 0x8b, 0xe4, 0x23, 0x21, 0x28, 0xad, 0xb7, 0x6b, 0x1, 0x79, 0xf9, 0x39, 0x21, 0x20, 0x8e, 0x74, 0xb3, 0xec, 0xe3, 0x11, 0x86, 0x22, 0xa4, 0x5f, 0x2d, 0x78, 0x84, 0xa6, 0x2f, 0x75, 0xc5, 0x5c, 0x42, 0xea, 0x90, 0xd0, 0xdb, 0x89, 0xdc, 0x5c, 0xfd, 0x4d, 0x88, 0x46, 0xe1, 0xdd, 0x2a, 0xf8, 0x44, 0xe4, 0xa4, 0x38, 0xf5, 0x57, 0xcb, 0x1e, 0x27, 0xeb, 0xdb, 0x7b, 0xc5, 0x62, 0x42, 0xfc, 0x1e, 0xad, 0xb7, 0x6b, 0x1, 0x7d, 0xb, 0x36, 0xe5, 0x12, 0x5, 0xda, 0xad, 0xf2, 0x4f, 0xc4, 0x84, 0x8a, 0x12, 0x7f, 0xbd, 0xbb, 0xc5, 0xa8, 0xfa, 0x16, 0x5f, 0x31, 0x98, 0x90, 0xbe, 0x4b, 0xea, 0x2d, 0x84, 0x5f, 0xee, 0x96, 0xe5, 0x1a, 0x8e, 0x4b, 0x53, 0x17, 0x8, 0xd5, 0x19, 0x53, 0x1b, 0xc3, 0x33, 0xb, 0xef, 0x91, 0xfa, 0x44, 0x7b, 0x41, 0x8a, 0x3a, 0x8f, 0x17, 0x20, 0x8a, 0x4, 0x24, 0xbd, 0x12, 0xa1, 0xa8, 0x10, 0x80, 0xbc, 0x92, 0x8a, 0x0, 0xf8, 0x7b, 0x41, 0x7, 0x5b, 0x9b, 0x62, 0xc9, 0xc6, 0x6a, 0xe7, 0x56, 0x46, 0x93, 0xcb, 0x16, 0xe6, 0xe1, 0x6, 0x35, 0x60, 0x86, 0x21, 0x9b, 0x6c, 0x8c, 0xc8, 0x85, 0x5d, 0x9f, 0xc, 0x2a, 0x30, 0x9a, 0x2f, 0xbf, 0x3d, 0x5d, 0xbc, 0x47, 0x93, 0x67, 0xf3, 0xe1, 0x78, 0xf6, 0x23, 0x82, 0x3d, 0x5d, 0x7e, 0x9b, 0xf8, 0xc8, 0x8f, 0x1c, 0xf3, 0x4b, 0x59, 0xb3, 0x31, 0x78, 0xb5, 0x37, 0x41, 0xa1, 0x60, 0x8, 0xd9, 0x51, 0xf8, 0x46, 0xf0, 0x38, 0x7b, 0xa3, 0x68, 0xe0, 0x99, 0x2c, 0xbb, 0x27, 0x5a, 0xf5, 0xbf, 0xce, 0x4c, 0x93, 0xfc, 0x18, 0x88, 0xeb, 0xb5, 0xdb, 0x61, 0xbc, 0x40, 0x51, 0x32, 0xff, 0xa0, 0xb6, 0xc7, 0x75, 0x45, 0xc, 0x7e, 0xb4, 0x14, 0xfe, 0x64, 0x32, 0xc, 0x9c, 0x18, 0x20, 0xc9, 0xd8, 0x7f, 0x20, 0x88, 0x2a, 0x8c, 0x25, 0x3a, 0x1e, 0xce, 0xbc, 0x68, 0xa2, 0x8f, 0x59, 0x86, 0x87, 0xd1, 0x56, 0x16, 0x40, 0x5c, 0xad, 0x84, 0x6f, 0x56, 0x6f, 0xaa, 0x9a, 0x75, 0x95, 0xbc, 0xa8, 0x8f, 0xdb, 0xe2, 0xa7, 0xc3, 0xb1, 0x58, 0x55, 0xed, 0xb7, 0x9f, 0xc7, 0xd9, 0x7b, 0x55, 0xb2, 0xbe, 0x2e, 0x27, 0x7f, 0x60, 0x47, 0xcc, 0x3b, 0x84, 0x9e, 0xc5, 0xb, 0x99, 0xb1, 0x42, 0x96, 0x67, 0xd6, 0x76, 0x7b, 0x1d, 0xe0, 0xd0, 0xf4, 0x1b, 0x2f, 0xbb, 0x6d, 0x55, 0x1e, 0x25, 0xcd, 0xbe, 0xe1, 0x6d, 0x2, 0xe, 0x1d, 0x8f, 0x65, 0xc1, 0xda, 0x73, 0xa5, 0x6f, 0xa, 0xef, 0xe, 0xeb, 0xa2, 0x1e, 0xf0, 0x87, 0x8b, 0x2e, 0xe1, 0x55, 0x6e, 0xe, 0x73, 0x42, 0xf9, 0xfa, 0xdd, 0x74, 0x61, 0xfa, 0x86, 0x78, 0x59, 0x5b, 0x75, 0xc, 0xfd, 0x36, 0xb8, 0x3d, 0x58, 0x2e, 0x7b, 0x8a, 0xbe, 0x2b, 0x38, 0xca, 0x66, 0x96, 0x23, 0x4d, 0x71, 0xd0, 0xac, 0x4e, 0xcc, 0xfa, 0xf0, 0x5a, 0xb5, 0x87, 0xf3, 0x6a, 0xbb, 0x38, 0x9c, 0x5b, 0xde, 0x3c, 0xe2, 0xf6, 0x39, 0x67, 0x64, 0xb8, 0x29, 0xd6, 0xcc, 0xa, 0x48, 0x86, 0xd7, 0x55, 0x51, 0x1f, 0x5e, 0x2e, 0x4e, 0x9c, 0x31, 0xfe, 0x7c, 0x9a, 0x34, 0x4c, 0xcc, 0xe8, 0x94, 0x4c, 0xcb, 0x6, 0xac, 0x1f, 0xbd, 0x5f, 0xc, 0x76, 0x4d, 0x1c, 0x7e, 0x88, 0x82, 0xa3, 0x59, 0xc3, 0x30, 0x67, 0x1, 0x47, 0xbd, 0xe1, 0x44, 0xc5, 0x27, 0xd, 0x63, 0x9c, 0xc2, 0xa2, 0x5d, 0x3c, 0x80, 0x84, 0x63, 0x68, 0xa1, 0x54, 0xfb, 0x9b, 0x44, 0x92, 0xc5, 0xe4, 0x91, 0x45, 0x84, 0x91, 0x51, 0x92, 0xe0, 0xfa, 0x6f, 0x95, 0x48, 0x31, 0x63, 0x74, 0x69, 0xf0, 0x55, 0x6b, 0x8a, 0x49, 0xf9, 0x26, 0x63, 0xac, 0xba, 0x5c, 0x87, 0x1e, 0x3, 0xbc, 0x44, 0xaf, 0x9e, 0x50, 0x50, 0xd7, 0xf8, 0x45, 0x36, 0xf5, 0xe, 0x12, 0x92, 0xef, 0x4d, 0xec, 0x1a, 0x7e, 0x6f, 0x81, 0x47, 0xe3, 0x7e, 0xf2, 0xae, 0x24, 0xf8, 0xd7, 0x16, 0x8, 0x1c, 0x24, 0xc0, 0xd8, 0xaa, 0xae, 0x8e, 0xb9, 0x35, 0xe7, 0xae, 0x45, 0xf6, 0x61, 0x7e, 0x67, 0x10, 0x84, 0xf8, 0xed, 0x82, 0xcb, 0x9d, 0x3d, 0x70, 0x9a, 0x21, 0x92, 0xca, 0xb2, 0x80, 0xbe, 0xe8, 0x75, 0x17, 0x65, 0x88, 0xf8, 0x4d, 0x4, 0xcc, 0x3e, 0x59, 0x1d, 0x30, 0xd9, 0xaa, 0xbd, 0xc9, 0x34, 0x9c, 0xd1, 0x56, 0x4d, 0x65, 0x53, 0x8f, 0xfd, 0xb9, 0x61, 0x6f, 0xad, 0x43, 0x1b, 0xcd, 0x87, 0xd3, 0x89, 0x6d, 0x7c, 0x89, 0xad, 0x83, 0xbd, 0x82, 0xc5, 0x27, 0x1e, 0xe1, 0x55, 0x23, 0xc1, 0x5b, 0x15, 0xc1, 0xdd, 0x16, 0x1d, 0xad, 0xd8, 0xb0, 0x2d, 0x6e, 0x93, 0x4, 0xba, 0x64, 0x9c, 0x12, 0xd0, 0x3c, 0xef, 0xde, 0x83, 0xf0, 0xa5, 0x20, 0xea, 0xa2, 0x8a, 0xde, 0xd, 0x71, 0xc5, 0xab, 0x63, 0xf, 0xfc, 0x2f, 0x27, 0xf6, 0x70, 0x18, 0x37, 0x21, 0x43, 0xf2, 0xe9, 0x5, 0x26, 0x94, 0x84, 0xc, 0x9b, 0x1e, 0xe6, 0x11, 0xfe, 0xf8, 0xc1, 0x7e, 0xba, 0x4f, 0x4d, 0xe9, 0x1c, 0xd2, 0xe0, 0xf2, 0xe8, 0x31, 0x3b, 0x66, 0x55, 0xce, 0xa7, 0x92, 0x18, 0xe9, 0xc, 0x9e, 0xd8, 0xff, 0x18, 0xb3, 0xb2, 0x47, 0xce, 0x78, 0x85, 0x95, 0x20, 0xc5, 0xb7, 0x71, 0x9, 0x92, 0x9e, 0x7d, 0xc, 0x32, 0x8, 0x84, 0xed, 0xf4, 0x78, 0x9, 0x9a, 0xf3, 0xd0, 0x20, 0xba, 0x83, 0x8b, 0x48, 0xe4, 0xd0, 0x38, 0xe8, 0x5e, 0x8e, 0xf6, 0xc6, 0x99, 0xba, 0x70, 0x12, 0xed, 0x8e, 0x4, 0x92, 0x11, 0xc1, 0x4e, 0xf1, 0x31, 0x11, 0x21, 0x4a, 0x10, 0xde, 0x9f, 0x9e, 0xc6, 0x80, 0xf7, 0x5a, 0xf3, 0xfd, 0x24, 0xf1, 0x87, 0xed, 0xe1, 0x50, 0xb7, 0xd5, 0x11, 0x91, 0x9c, 0xed, 0x6a, 0x8f, 0x99, 0x37, 0xfc, 0x15, 0xa3, 0x90, 0x4d, 0xb1, 0xab, 0xea, 0x6f, 0xf9, 0x7f, 0x16, 0xed, 0xa1, 0xff, 0xee, 0x3f, 0xca, 0xfa, 0x73, 0xc9, 0x23, 0x84, 0xf4, 0xfe, 0x5a, 0x9e, 0xcb, 0x77, 0x7d, 0xf3, 0xbb, 0xff, 0x6f, 0x27, 0x26, 0xae, 0x7e, 0xc3, 0x2c, 0xd5, 0xa0, 0x29, 0x4f, 0xd5, 0x26, 0xf6, 0x14, 0xc0, 0x34, 0xb, 0xf4, 0x7c, 0xd1, 0xa1, 0xe7, 0xaa, 0x3a, 0x38, 0x5d, 0xf6, 0x9, 0x47, 0x7f, 0x82, 0xf8, 0x4c, 0x37, 0x9c, 0xce, 0x37, 0x1, 0xa3, 0xce, 0x99, 0xc, 0x70, 0xae, 0x51, 0x65, 0x74, 0x15, 0x2f, 0x18, 0xbd, 0xfb, 0x76, 0x9d, 0x45, 0x56, 0x31, 0x53, 0x0, 0xe9, 0x8, 0x65, 0x11, 0xee, 0xc5, 0xe9, 0x13, 0x34, 0x65, 0xd6, 0x22, 0x6e, 0xc, 0xf7, 0x71, 0xe6, 0x3f, 0xb6, 0xf0, 0x31, 0x15, 0x4e, 0xb5, 0xe3, 0xbb, 0x36, 0xcc, 0x92, 0x86, 0x3, 0x54, 0xcd, 0x46, 0x71, 0x3a, 0x1d, 0xbe, 0x20, 0x2a, 0xe3, 0xc5, 0x7e, 0xcd, 0xe8, 0xf8, 0xc3, 0xa, 0x20, 0x43, 0xbe, 0x8, 0x6f, 0xe6, 0x34, 0x4b, 0xcf, 0x2b, 0xca, 0x75, 0x3, 0x33, 0x36, 0x29, 0x71, 0x24, 0x6, 0x2e, 0xc7, 0xa9, 0x3e, 0x2e, 0x9f, 0x54, 0xe8, 0x39, 0x37, 0x80, 0xa0, 0x8f, 0x0, 0x65, 0x9, 0x1a, 0x64, 0x81, 0xe6, 0x81, 0x2, 0x3f, 0x44, 0xcc, 0xeb, 0xca, 0x14, 0x64, 0x13, 0xb5, 0x7c, 0xcb, 0x32, 0xd1, 0xf2, 0xc4, 0x76, 0x7, 0x93, 0xa5, 0xf3, 0xd0, 0x93, 0xec, 0xa, 0x64, 0x49, 0x4e, 0x69, 0xf2, 0x54, 0x10, 0x56, 0x1e, 0x26, 0x53, 0x5d, 0x9c, 0xf6, 0xed, 0xc9, 0xf2, 0x32, 0x5d, 0xe2, 0x2, 0x9c, 0x3c, 0x40, 0x8b, 0x93, 0x2, 0xc2, 0xa, 0xec, 0xac, 0x32, 0x41, 0x61, 0xce, 0x72, 0x1, 0x56, 0xdc, 0x80, 0xaa, 0x24, 0xa2, 0x35, 0x78, 0x25, 0xef, 0x28, 0x93, 0x6c, 0xc8, 0x50, 0x6b, 0xee, 0x2f, 0xf3, 0x78, 0x38, 0x8a, 0xd9, 0x5f, 0x62, 0xe1, 0xc0, 0x7a, 0x88, 0xb9, 0xf5, 0x10, 0xc2, 0x9e, 0x0, 0xb, 0xf5, 0x38, 0x87, 0x73, 0x79, 0x6d, 0xf0, 0xdf, 0xc0, 0x79, 0xcc, 0xd2, 0xce, 0xc3, 0x79, 0x4f, 0x53, 0x5a, 0x41, 0x11, 0xa3, 0x9a, 0x1c, 0x62, 0xbf, 0x76, 0x94, 0xfb, 0xfa, 0x21, 0xba, 0x7e, 0x8b, 0xce, 0xf1, 0xf7, 0x63, 0x6c, 0x50, 0x80, 0x20, 0xb9, 0x4f, 0xe2, 0x9c, 0x76, 0x45, 0x6d, 0xda, 0x32, 0x70, 0x76, 0x72, 0x32, 0xa2, 0xa1, 0xa1, 0x7f, 0x73, 0xe1, 0xa1, 0x4b, 0x73, 0xe1, 0xa1, 0x17, 0x73, 0xe0, 0xfe, 0x60, 0xd6, 0x79, 0x8, 0xd5, 0x7b, 0xb4, 0xb0, 0xcb, 0x15, 0x5c, 0x73, 0x10, 0xb1, 0xc7, 0xfe, 0xcf, 0xa3, 0xa9, 0x9b, 0x82, 0xcc, 0xbc, 0xca, 0x2e, 0xb4, 0x88, 0x12, 0xc, 0xc6, 0xf3, 0x50, 0xf4, 0x99, 0xbe, 0xf7, 0x3b, 0x2f, 0x36, 0x2d, 0xaa, 0xf1, 0xee, 0xc8, 0xe7, 0x75, 0x1e, 0xce, 0x2d, 0xd2, 0xbb, 0x55, 0x3b, 0xa, 0x99, 0x54, 0x4c, 0xb9, 0x78, 0xf2, 0x55, 0x1b, 0xf5, 0x8a, 0xee, 0x3b, 0xa7, 0x81, 0x35, 0x61, 0xdc, 0xe4, 0x8d, 0x46, 0x41, 0xa7, 0xd7, 0xd5, 0x89, 0xad, 0xe0, 0x2e, 0x4c, 0x50, 0x34, 0xc8, 0x21, 0x28, 0x4e, 0x71, 0x69, 0x78, 0xea, 0xbd, 0x5b, 0xd8, 0xdd, 0xe1, 0x45, 0xa0, 0x14, 0x5d, 0x59, 0xb0, 0xe7, 0x39, 0xa1, 0x8e, 0xea, 0x2a, 0x3a, 0xbe, 0x4b, 0x56, 0xcd, 0xd1, 0xee, 0x91, 0xe7, 0x35, 0xbc, 0x62, 0xa0, 0xe7, 0x72, 0x57, 0xab, 0x91, 0xc2, 0x90, 0xa, 0xca, 0x2e, 0x22, 0xca, 0x50, 0xc2, 0xc9, 0xba, 0x17, 0x18, 0xd4, 0x4c, 0x12, 0xe9, 0xde, 0x7a, 0xe0, 0xe6, 0xed, 0x22, 0xb1, 0xb8, 0xbd, 0x30, 0xe2, 0x20, 0x8a, 0x43, 0x2a, 0xa7, 0xce, 0x16, 0xd0, 0x4d, 0x97, 0x2a, 0x3f, 0xa8, 0x20, 0x27, 0xe1, 0xb7, 0x9c, 0x7a, 0xc8, 0x24, 0xda, 0x74, 0x52, 0x6a, 0x5e, 0x51, 0x60, 0x14, 0x80, 0x36, 0x1d, 0x28, 0xc, 0xa9, 0x9c, 0xba, 0xcf, 0xdb, 0xbd, 0xc, 0xbb, 0xfc, 0x62, 0x5b, 0x1a, 0x3e, 0xf5, 0xa5, 0x43, 0x23, 0x3e, 0xdb, 0x34, 0x59, 0x6c, 0x3f, 0x81, 0x24, 0x5f, 0xc4, 0x96, 0x58, 0xdc, 0x9f, 0xb3, 0x89, 0x2c, 0xcc, 0xa8, 0x93, 0x34, 0xda, 0xaa, 0x2e, 0x8b, 0xd3, 0xa6, 0xfa, 0xaa, 0x71, 0xcc, 0x6f, 0x83, 0xe0, 0x3e, 0xbb, 0x64, 0xf0, 0xbc, 0xe4, 0x0, 0x3d, 0x40, 0x34, 0x28, 0xeb, 0x7a, 0xb0, 0x3d, 0x9c, 0xaa, 0xdf, 0x38, 0xa0, 0xee, 0xad, 0xd, 0xc9, 0x20, 0x5d, 0x67, 0xe0, 0x8b, 0x6b, 0x10, 0x24, 0x13, 0x1c, 0x99, 0xc4, 0x50, 0x34, 0x19, 0xb8, 0x20, 0xa0, 0xf3, 0x39, 0x69, 0x1a, 0x71, 0x5f, 0x7c, 0xd6, 0x70, 0xfe, 0x9, 0x92, 0xf9, 0xaa, 0x80, 0xde, 0xc, 0x2, 0x28, 0x4e, 0xb2, 0x87, 0x2e, 0x57, 0x65, 0x3c, 0x64, 0x95, 0xe8, 0xa2, 0xba, 0x38, 0x6, 0x28, 0x5e, 0xd7, 0xd4, 0x30, 0xf9, 0xc3, 0x82, 0xf4, 0x6e, 0x94, 0x85, 0x9b, 0x14, 0x8d, 0x64, 0x14, 0x56, 0x7e, 0xfa, 0x2f, 0xa6, 0x33, 0xe5, 0x75, 0xc2, 0x7b, 0xde, 0xa0, 0x84, 0x9e, 0x7a, 0x5, 0xaa, 0x94, 0xd0, 0x1c, 0xb2, 0xdd, 0x3b, 0xb4, 0x29, 0xd6, 0x7c, 0xa0, 0xc9, 0x88, 0xa6, 0x41, 0x1b, 0xc1, 0x95, 0xba, 0x23, 0xe7, 0x50, 0xa8, 0x40, 0x90, 0xca, 0x8, 0xf0, 0x4a, 0xf3, 0xc8, 0xa5, 0xdb, 0xeb, 0x50, 0xce, 0x85, 0xd5, 0xda, 0x92, 0xeb, 0xe1, 0x3b, 0xbc, 0xae, 0x5, 0x3, 0xbb, 0x82, 0xdd, 0x9a, 0x3f, 0x54, 0xbb, 0xe3, 0xe1, 0xd4, 0x16, 0xc2, 0x16, 0x99, 0x48, 0xae, 0xf6, 0x69, 0x14, 0x8, 0xdf, 0x56, 0xeb, 0xd2, 0xd9, 0x98, 0x80, 0xc0, 0x66, 0xcb, 0xcc, 0xa4, 0xc3, 0x15, 0x84, 0x56, 0xfb, 0xcf, 0x95, 0x7c, 0x6c, 0x4a, 0xfc, 0x5b, 0xd5, 0x7c, 0xbd, 0x43, 0xef, 0x78, 0x88, 0x91, 0xae, 0x20, 0xce, 0x47, 0x54, 0x79, 0xf6, 0x21, 0xeb, 0x15, 0xb, 0xc4, 0x29, 0xf8, 0x5b, 0x43, 0xc1, 0x80, 0x2b, 0x1c, 0xca, 0xf0, 0x5, 0x0, 0x59, 0xc, 0xc9, 0x78, 0xb1, 0x61, 0x4a, 0xe5, 0x2d, 0xe8, 0x5e, 0xff, 0xcc, 0xd7, 0xeb, 0x3f, 0x57, 0xe5, 0x17, 0x8e, 0xa6, 0x56, 0x9f, 0xd6, 0xe5, 0xe7, 0x6a, 0x55, 0x4a, 0xa3, 0x7b, 0x1d, 0xaa, 0xfa, 0xc, 0xea, 0x97, 0x3e, 0xf8, 0x96, 0xad, 0xe3, 0xa4, 0xc8, 0x17, 0x27, 0x91, 0x24, 0x1f, 0x77, 0xb7, 0x86, 0xdf, 0x21, 0x34, 0xa0, 0x64, 0x92, 0x7c, 0xdc, 0xe3, 0xa9, 0xda, 0xb7, 0xde, 0x4f, 0x14, 0x27, 0x20, 0x9, 0x53, 0xfd, 0x1c, 0xcd, 0xe, 0x7e, 0x87, 0xd0, 0x80, 0x98, 0x49, 0xf2, 0x71, 0xbf, 0x36, 0xf0, 0x3b, 0x84, 0x6, 0x94, 0x4c, 0x92, 0xa7, 0xfd, 0x5e, 0x5b, 0x9a, 0x85, 0x44, 0x33, 0x93, 0x7b, 0x9c, 0x3f, 0x8a, 0x85, 0x44, 0x4b, 0x88, 0xd4, 0x51, 0x61, 0x9e, 0x30, 0x44, 0x69, 0xb7, 0xda, 0x13, 0x9, 0x1b, 0xb0, 0xfe, 0xa, 0x9, 0xad, 0x61, 0x45, 0xdb, 0x2d, 0x9d, 0x8f, 0x87, 0x3a, 0x6, 0x19, 0x3b, 0xf1, 0x8f, 0xf5, 0xff, 0x9b, 0x69, 0x48, 0x61, 0x7a, 0x8f, 0xa2, 0xde, 0x49, 0xc5, 0x63, 0x8, 0x26, 0xa2, 0x14, 0xbd, 0x5, 0x6a, 0xf5, 0x7e, 0xa3, 0x29, 0xe7, 0xe9, 0x69, 0xe4, 0x94, 0xd3, 0xec, 0x3a, 0xb6, 0x18, 0x40, 0xc, 0x5a, 0xcc, 0x87, 0xd1, 0x2d, 0xc6, 0x94, 0x1c, 0xb4, 0x58, 0x90, 0x8f, 0x6c, 0xb1, 0x9b, 0x6b, 0xd5, 0xb9, 0x1d, 0x6f, 0xa7, 0xdc, 0xbd, 0x75, 0xef, 0xa5, 0x7d, 0x77, 0x9b, 0xcb, 0x85, 0x7d, 0xbf, 0x9c, 0xd1, 0x88, 0x6f, 0x75, 0x80, 0x82, 0x76, 0xeb, 0x8e, 0x8d, 0xe, 0x10, 0x83, 0x46, 0xf7, 0x61, 0x74, 0xa3, 0x33, 0xcb, 0xb, 0x1a, 0x3d, 0xc8, 0x97, 0x6e, 0xf4, 0xce, 0xd5, 0xba, 0xbd, 0xd5, 0xbb, 0x93, 0xbe, 0xa3, 0xd9, 0x6f, 0x25, 0x7e, 0x77, 0xbb, 0x8f, 0xc4, 0xa2, 0x3f, 0x20, 0x59, 0xbf, 0x74, 0x6c, 0x61, 0x80, 0x18, 0xb4, 0xb0, 0xf, 0xa3, 0x5b, 0x98, 0x79, 0x69, 0xd0, 0xc2, 0x41, 0xbe, 0x74, 0xb, 0x23, 0x15, 0xb8, 0xbd, 0x2d, 0x31, 0x22, 0x77, 0xb4, 0x1a, 0x4d, 0xe6, 0xd6, 0xf6, 0x9, 0xac, 0xbb, 0x1c, 0x2b, 0x41, 0x4f, 0xe5, 0xb9, 0xd8, 0x9b, 0x6d, 0x87, 0xa2, 0x8, 0x2c, 0x69, 0x9a, 0x62, 0x42, 0x2d, 0x15, 0x49, 0xd0, 0x4f, 0xd3, 0x24, 0x8d, 0xcc, 0x54, 0x66, 0xa0, 0x2, 0x44, 0x66, 0x31, 0x14, 0xba, 0xb8, 0x23, 0xa3, 0x8e, 0x3a, 0xeb, 0xe2, 0x6, 0x6a, 0x8b, 0x80, 0x69, 0xcd, 0x95, 0x63, 0x39, 0xa0, 0xbc, 0x58, 0x6e, 0x42, 0x7f, 0xb1, 0x2a, 0x74, 0xd4, 0x5a, 0x34, 0x6b, 0x57, 0x5d, 0x8d, 0x64, 0xbe, 0x4d, 0x43, 0x15, 0x21, 0xd5, 0x66, 0x6e, 0xcd, 0xfd, 0x66, 0x53, 0x53, 0x2c, 0x6c, 0xdb, 0x5a, 0xce, 0x16, 0x82, 0xdf, 0x62, 0x82, 0x20, 0xf, 0x99, 0xd9, 0x95, 0xdc, 0xb1, 0x7a, 0xd6, 0x5b, 0xbc, 0xef, 0x22, 0x6f, 0x49, 0xe8, 0x13, 0x9f, 0xe8, 0xa9, 0xfe, 0x85, 0xb7, 0x7a, 0xa4, 0xb2, 0xb2, 0x9, 0x4f, 0x79, 0xe2, 0xb7, 0x50, 0x3a, 0x64, 0xd5, 0x11, 0xd9, 0xf9, 0x41, 0x3, 0xef, 0x91, 0x79, 0x39, 0x5d, 0x56, 0x7c, 0x90, 0x71, 0xfe, 0xf5, 0xd3, 0x2, 0x1c, 0x97, 0x8f, 0xd2, 0xe5, 0xc3, 0xed, 0x17, 0xaf, 0x56, 0xe2, 0xb8, 0x45, 0x40, 0x5f, 0xcc, 0xaa, 0xd4, 0x95, 0x84, 0xbe, 0xf3, 0xcb, 0x3d, 0x4d, 0x67, 0x1e, 0x56, 0x16, 0xb3, 0x30, 0x79, 0x80, 0xbe, 0xef, 0xfc, 0x72, 0xf1, 0xf5, 0x1b, 0x75, 0x72, 0xeb, 0x56, 0x9c, 0x7e, 0xed, 0xc3, 0x1f, 0x1e, 0x75, 0xf5, 0xe0, 0x8e, 0x40, 0x50, 0x27, 0x95, 0xfb, 0xce, 0x2f, 0x2f, 0x56, 0xab, 0x7a, 0x17, 0x4a, 0x60, 0xf0, 0x83, 0xe5, 0x7d, 0xfb, 0xe9, 0xf1, 0xa1, 0x9f, 0x2d, 0x63, 0x53, 0x6e, 0x7d, 0xe2, 0x25, 0xba, 0xfc, 0x67, 0xa2, 0x87, 0xee, 0xca, 0xfd, 0xf9, 0x2, 0xb5, 0xc4, 0xec, 0x4, 0x74, 0x54, 0x31, 0x8f, 0x96, 0x78, 0x22, 0xde, 0x6b, 0x94, 0x5, 0xda, 0xde, 0x62, 0x11, 0x62, 0x28, 0x4f, 0x76, 0xf9, 0xc1, 0x4c, 0x6f, 0x2f, 0x5b, 0x55, 0xda, 0xd7, 0x71, 0x19, 0xf9, 0x40, 0x46, 0x2f, 0x74, 0x77, 0x32, 0x14, 0xac, 0x57, 0xf0, 0x47, 0x22, 0x7e, 0xe2, 0x1c, 0xbd, 0xef, 0x7, 0x29, 0x17, 0x7f, 0xc3, 0x1e, 0x6c, 0xcf, 0x33, 0xd5, 0x2c, 0x4f, 0xbc, 0x63, 0x6b, 0x4a, 0xae, 0x20, 0x7a, 0x45, 0x1f, 0x4f, 0x46, 0x1f, 0xd6, 0x30, 0x34, 0x4, 0x70, 0x77, 0x6e, 0xcb, 0x75, 0x3f, 0x48, 0xf1, 0xdf, 0x5c, 0x0, 0x51, 0x11, 0xe4, 0x85, 0xdd, 0x7e, 0x90, 0xb4, 0x35, 0x49, 0xf6, 0x5a, 0x71, 0x98, 0x64, 0xb1, 0xec, 0xe5, 0xdf, 0x30, 0x69, 0xdb, 0xf, 0xb, 0xc, 0xcb, 0xb, 0x8b, 0xb, 0x4b, 0xb, 0xb, 0xb, 0xca, 0xa2, 0x4f, 0xda, 0x57, 0xfb, 0xe3, 0x99, 0xf9, 0xa, 0x26, 0x15, 0xf6, 0x5b, 0x47, 0x90, 0xfd, 0x61, 0xbc, 0x9c, 0x94, 0x33, 0x7e, 0x52, 0x77, 0x5b, 0xae, 0x7e, 0x65, 0x6a, 0xd2, 0xab, 0x8b, 0x65, 0x59, 0xf7, 0x87, 0xdb, 0xb2, 0x3e, 0xea, 0xb9, 0x37, 0xdf, 0x9b, 0x3a, 0x28, 0x80, 0xf8, 0x3b, 0xa9, 0xa7, 0xa2, 0xac, 0x41, 0xb1, 0x5e, 0xf3, 0x80, 0x95, 0xf2, 0x87, 0x5c, 0xd5, 0x13, 0x49, 0x5e, 0xc8, 0xe9, 0xe1, 0xb6, 0x68, 0x6c, 0x8, 0x70, 0xbe, 0x44, 0x77, 0x3a, 0xd4, 0x3, 0xcd, 0x7, 0x84, 0x89, 0x45, 0x38, 0x8d, 0xb0, 0x29, 0xcb, 0x35, 0xb7, 0x76, 0x1e, 0x8e, 0x65, 0xdc, 0x37, 0x7, 0xe, 0x5a, 0xc8, 0x14, 0xe8, 0xcc, 0x12, 0xb7, 0x3c, 0x9d, 0xe, 0x27, 0x94, 0x21, 0x5, 0x89, 0xb0, 0xa3, 0x30, 0x42, 0x66, 0xb4, 0x2d, 0x3, 0x48, 0x1d, 0x58, 0x31, 0xef, 0xb, 0x20, 0xcc, 0x18, 0x58, 0x84, 0x1d, 0x83, 0x13, 0x32, 0xa4, 0x4d, 0xb1, 0x83, 0x96, 0x60, 0x9, 0x96, 0xa4, 0xcf, 0x58, 0x13, 0x72, 0x81, 0x60, 0x94, 0x53, 0x88, 0x80, 0x36, 0xb4, 0x44, 0xe8, 0x6e, 0xda, 0x98, 0x8f, 0xed, 0x9, 0xf3, 0xc8, 0xc3, 0x29, 0x83, 0x1f, 0xba, 0x20, 0x98, 0xa4, 0x7c, 0x26, 0x79, 0x7f, 0x84, 0xe1, 0xe, 0x8e, 0x55, 0x5d, 0x37, 0xc2, 0x3c, 0x8b, 0xbc, 0x3, 0xd6, 0xe5, 0xf4, 0x4f, 0xb1, 0x52, 0xdb, 0x2b, 0x7c, 0x7d, 0x6, 0x7d, 0x4, 0x76, 0xa, 0xf1, 0xac, 0x78, 0x5f, 0xfe, 0x3, 0x1f, 0x19, 0xd7, 0x49, 0xc5, 0x5, 0x5e, 0x7, 0x94, 0x27, 0x29, 0xcd, 0xe9, 0xaf, 0x69, 0xe4, 0x48, 0xbb, 0x46, 0x1a, 0xa9, 0x7b, 0x7, 0x5d, 0x45, 0x55, 0x50, 0xaf, 0xcf, 0x14, 0xf1, 0xe7, 0x67, 0x8a, 0xf8, 0xfb, 0x33, 0x50, 0x55, 0x52, 0x4f, 0x47, 0x5c, 0x6e, 0x7f, 0x8c, 0xe3, 0xae, 0xb7, 0x29, 0x6e, 0x78, 0x23, 0xc3, 0xd, 0xce, 0x7f, 0xb9, 0xfd, 0xb9, 0x83, 0xbb, 0xa2, 0xff, 0xdf, 0xf0, 0xa, 0x81, 0x13, 0xa5, 0xfe, 0x72, 0x73, 0xc0, 0xff, 0x7b, 0x82, 0xe0, 0x93, 0x91, 0xf8, 0xd5, 0x6d, 0x73, 0xc7, 0x3a, 0xc4, 0xef, 0x46, 0x53, 0xe7, 0x20, 0xbc, 0x3e, 0xd4, 0x6e, 0xcf, 0xbb, 0xe5, 0xbe, 0xa8, 0xea, 0x4b, 0xea, 0xf4, 0x38, 0xb8, 0x34, 0x1, 0x2e, 0x61, 0x4, 0xb9, 0xe0, 0xc1, 0x92, 0xf9, 0x7b, 0xf7, 0x88, 0x6e, 0xdf, 0x3d, 0xf3, 0x9c, 0x38, 0xab, 0x1, 0x67, 0x8, 0xf0, 0x2e, 0xbe, 0x73, 0x30, 0x4, 0x32, 0xf7, 0xff, 0x0, 0x50, 0x53, 0x8f, 0xd6, 0x78, 0x8a, 0x1, 0x0, 0x0, 0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0xbd, 0x5a, 0x7b, 0x6f, 0xe3, 0x36, 0x12, 0xff, 0x5b, 0x5, 0xfa, 0x1d, 0x58, 0xef, 0x16, 0x92, 0x2f, 0xb2, 0xe4, 0xb8, 0x9b, 0xeb, 0xc1, 0x59, 0x2f, 0xd0, 0xcb, 0x6e, 0xd0, 0x16, 0xed, 0x66, 0x6f, 0x13, 0xe0, 0x70, 0x58, 0x2c, 0x16, 0xb4, 0x44, 0xdb, 0x6c, 0x64, 0x49, 0xa0, 0xe8, 0x3c, 0x10, 0xf8, 0xbb, 0x1f, 0x87, 0xf, 0x89, 0x7a, 0xc5, 0xce, 0xab, 0x6, 0xe2, 0x58, 0xd4, 0xcc, 0x6f, 0x86, 0x43, 0xce, 0x70, 0x66, 0xa4, 0xd7, 0xde, 0x62, 0x93, 0x46, 0x9c, 0x66, 0xa9, 0x37, 0xbc, 0xfb, 0xfe, 0xbb, 0xef, 0xbf, 0x73, 0xae, 0x30, 0x43, 0x45, 0x84, 0xd3, 0x94, 0xa6, 0x4b, 0x34, 0x43, 0xe3, 0x63, 0x31, 0x66, 0xd, 0x7f, 0x26, 0xc5, 0x26, 0xe1, 0xb3, 0x74, 0x93, 0x24, 0xc7, 0x92, 0xde, 0xf0, 0xa3, 0x6b, 0xba, 0xa0, 0x27, 0x59, 0x9a, 0x92, 0x88, 0xff, 0x99, 0xc5, 0x38, 0xf1, 0x68, 0xac, 0x21, 0x1d, 0xba, 0xf0, 0x2c, 0x5e, 0xc9, 0x3c, 0x84, 0x71, 0x87, 0x11, 0xbe, 0x61, 0xa9, 0x2, 0x92, 0x22, 0xd6, 0xc0, 0x29, 0xc4, 0xbe, 0xf6, 0xdc, 0x57, 0x91, 0x2, 0x1b, 0xc9, 0x31, 0x77, 0x78, 0x6c, 0x68, 0x70, 0x2e, 0x8, 0x2a, 0xbc, 0x0, 0xe7, 0x5f, 0x68, 0xfc, 0x55, 0x83, 0x48, 0xe2, 0x60, 0x41, 0xd3, 0x58, 0x20, 0xc8, 0x8b, 0x91, 0xc1, 0xe1, 0x94, 0x27, 0xc4, 0x1d, 0x6, 0x9c, 0xdc, 0x70, 0xcf, 0xd5, 0xaa, 0x22, 0x9e, 0x21, 0xf7, 0x0, 0xe7, 0x41, 0x51, 0x8, 0x7d, 0x8f, 0xb5, 0xb6, 0xe2, 0x9a, 0xa4, 0xd1, 0x6c, 0x36, 0x86, 0x19, 0x38, 0xf7, 0xa2, 0xe6, 0xb8, 0x28, 0xae, 0x33, 0x16, 0xb, 0xe0, 0x15, 0x8d, 0x89, 0xa7, 0x30, 0xee, 0xe3, 0x48, 0x33, 0x9b, 0xa9, 0x58, 0x65, 0xd7, 0x9a, 0x69, 0xb, 0x5f, 0x24, 0x29, 0xc8, 0x43, 0x84, 0x5a, 0xfc, 0xfb, 0xb, 0x2d, 0x35, 0xdd, 0x57, 0xd0, 0x88, 0xa6, 0xf9, 0x86, 0xb, 0xce, 0x2b, 0xb1, 0xb0, 0xae, 0x5b, 0xea, 0x5b, 0x99, 0x3c, 0xc6, 0x1c, 0x7b, 0x2e, 0xce, 0x5d, 0x1f, 0xe7, 0x6, 0xb9, 0xb5, 0x8a, 0x28, 0x28, 0xe1, 0x39, 0x49, 0x79, 0xa0, 0x6f, 0xd6, 0xa7, 0xb1, 0x93, 0xab, 0xd8, 0x44, 0x11, 0x29, 0x8a, 0xba, 0xc5, 0xf7, 0x95, 0x25, 0xb6, 0x75, 0x9d, 0xb1, 0x9a, 0x82, 0xfc, 0xf6, 0xee, 0x40, 0x95, 0x29, 0x67, 0x1b, 0xe2, 0xcf, 0x71, 0x74, 0x19, 0xb3, 0x2c, 0x9f, 0x2e, 0xb0, 0x58, 0x95, 0xad, 0x3d, 0xad, 0x1d, 0x66, 0x5a, 0x64, 0xd1, 0xa6, 0x50, 0x2, 0xb6, 0x6d, 0x37, 0x39, 0x17, 0x9b, 0xd7, 0xf8, 0x9b, 0x63, 0x9c, 0x6d, 0x76, 0x28, 0xd5, 0x9, 0x43, 0xd0, 0xd, 0x31, 0xb9, 0xb7, 0x7d, 0x4, 0xca, 0xa0, 0x9c, 0x65, 0x4b, 0x31, 0x50, 0x18, 0xe1, 0xc0, 0x32, 0x52, 0x14, 0x6d, 0x23, 0xc8, 0x9b, 0x86, 0xc3, 0xb6, 0xac, 0x24, 0x8, 0xf0, 0x5f, 0xf8, 0xc6, 0x83, 0x9f, 0xc8, 0x51, 0xdb, 0xcc, 0xe1, 0xb7, 0x39, 0x99, 0xba, 0x9f, 0xce, 0xce, 0x2f, 0x5c, 0x5f, 0x8d, 0x6c, 0x58, 0x32, 0x75, 0x43, 0x9c, 0xd3, 0x10, 0xb4, 0xd, 0x1, 0xd1, 0xdc, 0x82, 0x65, 0x9e, 0x82, 0x3, 0xfb, 0x70, 0xa5, 0xc6, 0xf4, 0x7a, 0x4c, 0x51, 0x19, 0x4b, 0x80, 0xca, 0xcc, 0xcf, 0xb1, 0xa6, 0x38, 0x3e, 0xae, 0x8d, 0x29, 0x7, 0x16, 0xde, 0xc, 0xf4, 0xd5, 0x2d, 0x6d, 0x2, 0x33, 0x7, 0x6d, 0x4, 0x35, 0x5f, 0x4d, 0xd2, 0xb6, 0x82, 0xed, 0x7, 0xdd, 0x86, 0xa8, 0x6f, 0x7a, 0xe9, 0xe7, 0x20, 0x57, 0xc4, 0x8f, 0x6f, 0x51, 0xb6, 0x49, 0x79, 0xe5, 0xee, 0x6d, 0x1, 0x23, 0xb2, 0xce, 0xf9, 0x6d, 0x4b, 0x4c, 0x8b, 0x8c, 0xe3, 0xb9, 0x8c, 0x31, 0x76, 0x28, 0xd0, 0x8e, 0xed, 0x94, 0xbe, 0xbd, 0x4b, 0x46, 0x9d, 0xb9, 0x57, 0x46, 0x6d, 0x61, 0x3b, 0x8, 0x11, 0x9f, 0x67, 0xf1, 0x2d, 0xe2, 0x4c, 0xd0, 0x32, 0xb2, 0xce, 0xae, 0x0, 0x14, 0x85, 0xa1, 0x14, 0x83, 0x24, 0x4a, 0xc5, 0x1b, 0x86, 0x45, 0xc6, 0x38, 0x32, 0x97, 0xda, 0x30, 0x7a, 0x69, 0x2, 0x88, 0x8f, 0xe2, 0x76, 0x75, 0x58, 0x60, 0x7f, 0x3e, 0xbc, 0x53, 0xd1, 0x1b, 0xcd, 0x3, 0x26, 0x82, 0x27, 0x1a, 0x21, 0xac, 0x7e, 0x6c, 0x6d, 0x9d, 0x16, 0x19, 0xf3, 0xa8, 0x58, 0x77, 0xfa, 0xb6, 0x66, 0xeb, 0x63, 0x7a, 0x70, 0xa0, 0x8d, 0x8d, 0xd4, 0xc7, 0xec, 0xa6, 0xea, 0xb2, 0x8c, 0xf5, 0x9a, 0xf3, 0xb, 0xfd, 0x7a, 0xdc, 0x41, 0xc2, 0x99, 0x3a, 0x2f, 0xde, 0x72, 0xf6, 0x4e, 0x7, 0x26, 0x8b, 0x82, 0xb3, 0x32, 0x32, 0x8d, 0x68, 0xec, 0xfa, 0xd4, 0xd8, 0x15, 0x95, 0x1f, 0xa7, 0x35, 0x20, 0x61, 0xe3, 0x6f, 0x29, 0x5e, 0x13, 0x83, 0x1d, 0x97, 0xd8, 0x36, 0xa1, 0x26, 0x52, 0x47, 0x4a, 0xed, 0x10, 0xe9, 0x24, 0xc3, 0x79, 0x4e, 0xd2, 0xf8, 0x22, 0xf3, 0x38, 0xab, 0x6c, 0xd4, 0x96, 0x1b, 0xad, 0x84, 0xbb, 0x90, 0xa4, 0x14, 0x8d, 0xa2, 0x44, 0xc4, 0x97, 0xd9, 0x0, 0xa4, 0x8c, 0x22, 0x11, 0xcb, 0x8, 0x1b, 0xf4, 0xa9, 0xa3, 0x79, 0x4b, 0x8d, 0xf4, 0x75, 0x7, 0x71, 0x18, 0x5a, 0xe4, 0x7b, 0x6a, 0x26, 0xe, 0xc5, 0x5d, 0x5a, 0xb5, 0x95, 0x32, 0x2b, 0x20, 0x98, 0xe1, 0x70, 0x80, 0x93, 0xb5, 0x43, 0x9d, 0xe2, 0x9a, 0xf2, 0x68, 0xa5, 0x4f, 0x5e, 0xe3, 0x87, 0xd6, 0x7d, 0x27, 0xc2, 0x5, 0x41, 0xe3, 0x69, 0xfb, 0x86, 0xa3, 0x14, 0x53, 0x53, 0x1e, 0x9c, 0x7d, 0xfa, 0xf0, 0x71, 0xd0, 0x81, 0xef, 0x38, 0x73, 0x46, 0xf0, 0xe5, 0x71, 0xf, 0xf0, 0xe1, 0x4e, 0xe0, 0x93, 0x3f, 0xce, 0xce, 0x3f, 0xbc, 0x7f, 0x4, 0xf4, 0xe4, 0xe5, 0xa0, 0x7f, 0x7a, 0x39, 0xe8, 0x37, 0x2f, 0x2, 0x1d, 0x93, 0x5, 0x16, 0xa1, 0xe9, 0x25, 0xb0, 0xb7, 0x5d, 0xee, 0x0, 0x88, 0x7b, 0xee, 0xed, 0x82, 0x2e, 0x53, 0x6c, 0x39, 0xdd, 0xde, 0x5e, 0x27, 0x53, 0x63, 0xc9, 0xfc, 0x2d, 0x8f, 0xe0, 0x34, 0x3b, 0x1c, 0x8f, 0xff, 0x21, 0xf6, 0x31, 0x4, 0xc3, 0x70, 0x72, 0xf4, 0xcf, 0x60, 0x7c, 0x2f, 0x4f, 0x91, 0xe3, 0x54, 0x4b, 0x95, 0x3f, 0xb5, 0xd8, 0x4, 0xcf, 0x49, 0x32, 0x78, 0xf7, 0x36, 0x84, 0xc1, 0x4e, 0xb9, 0x16, 0xbf, 0xb2, 0x5a, 0xa5, 0x44, 0xc0, 0xb3, 0x53, 0x7a, 0x43, 0x44, 0x3e, 0xb7, 0x98, 0xb8, 0xc3, 0x3, 0xf7, 0x47, 0xb7, 0x73, 0xe6, 0x90, 0x97, 0x57, 0x8a, 0xbf, 0x43, 0x3f, 0x8f, 0x87, 0xb6, 0x56, 0x1, 0x8e, 0xe3, 0x13, 0xd0, 0xc6, 0x73, 0xa5, 0x36, 0xa3, 0x32, 0xf1, 0x6a, 0x2b, 0x3, 0x47, 0x1b, 0x6a, 0xe2, 0xbd, 0xd9, 0x81, 0x77, 0x8d, 0x59, 0x2a, 0xf3, 0xb1, 0x1e, 0x3c, 0x6b, 0x42, 0x4d, 0xd6, 0x18, 0xa7, 0x4b, 0xc2, 0xba, 0xa7, 0x55, 0x13, 0x59, 0x2e, 0xbe, 0x59, 0xe1, 0xee, 0xb8, 0xa9, 0xee, 0xed, 0xdc, 0x2b, 0x22, 0x98, 0x95, 0x24, 0x9d, 0xc7, 0x2d, 0xe4, 0x7e, 0x94, 0x15, 0xdc, 0x1b, 0x76, 0xf1, 0x37, 0xcf, 0x1a, 0x6b, 0xcf, 0xea, 0x9f, 0x5b, 0x9d, 0x67, 0x2d, 0x30, 0x4d, 0xa6, 0xcd, 0xda, 0xac, 0x95, 0x4b, 0xfd, 0x9d, 0xe9, 0xd2, 0x7e, 0x19, 0xd1, 0xce, 0x84, 0x48, 0x4f, 0x53, 0xfe, 0x13, 0x99, 0x82, 0x3a, 0xf6, 0xb7, 0xbd, 0xa5, 0xa4, 0x7, 0x47, 0xaa, 0x9f, 0x5f, 0x97, 0xb5, 0x24, 0x78, 0x4e, 0x9e, 0x15, 0xfc, 0xbd, 0x38, 0x53, 0x84, 0xdb, 0xdc, 0xd, 0x80, 0x60, 0x30, 0x95, 0x64, 0x3, 0x41, 0x37, 0x98, 0x8a, 0xaf, 0xed, 0xc3, 0xb, 0x90, 0x87, 0x94, 0x12, 0xcf, 0x50, 0x80, 0x3c, 0x3d, 0x2b, 0x37, 0xaa, 0xdb, 0x89, 0xf9, 0xef, 0xe7, 0x67, 0x1f, 0x83, 0x82, 0x33, 0x21, 0x83, 0x2e, 0x6e, 0x3d, 0x63, 0xa7, 0xa1, 0xa6, 0xd1, 0x9a, 0x5c, 0x0, 0x34, 0x12, 0x19, 0x51, 0x9e, 0xd0, 0x8, 0x83, 0xc5, 0xc3, 0xbf, 0x8a, 0xac, 0x4c, 0xf1, 0x4d, 0x3a, 0xdf, 0x97, 0xcd, 0x3f, 0xce, 0xa8, 0xce, 0x83, 0xec, 0xda, 0xde, 0x54, 0x8f, 0xa8, 0xed, 0x1e, 0x28, 0x16, 0xad, 0x7e, 0x32, 0xe9, 0x8b, 0xe3, 0xe8, 0x2e, 0xc1, 0x67, 0x92, 0xe0, 0x5b, 0x94, 0xa, 0x7f, 0xd2, 0x8, 0x24, 0x56, 0x1d, 0x3, 0xd8, 0x6f, 0x7, 0xae, 0xd8, 0xa9, 0x7c, 0x85, 0x68, 0x2e, 0xac, 0x79, 0x20, 0xb3, 0x54, 0x9a, 0x57, 0x79, 0xbb, 0xfe, 0x2f, 0xb, 0x3e, 0x8e, 0xb9, 0xae, 0x7, 0xf7, 0x74, 0xf3, 0xc7, 0x95, 0xce, 0xce, 0x63, 0x37, 0xaf, 0xf3, 0x84, 0x2, 0xba, 0x3d, 0xc7, 0x9a, 0x87, 0xb7, 0xdd, 0x3b, 0x5a, 0x91, 0xe8, 0xf2, 0x37, 0x38, 0x50, 0x53, 0xc2, 0x3d, 0xdb, 0xb1, 0xb, 0x89, 0xf1, 0x8d, 0xea, 0x7b, 0x33, 0x19, 0x4d, 0xe4, 0xd8, 0xc8, 0x8c, 0xe9, 0xc3, 0xa2, 0x41, 0x69, 0xd2, 0x6, 0x40, 0x16, 0xa, 0x6, 0x41, 0x30, 0x78, 0x9a, 0x73, 0xd9, 0x2a, 0xd6, 0x5c, 0xcc, 0x75, 0x9f, 0xd5, 0x99, 0x4c, 0x11, 0xaa, 0xe6, 0x33, 0x9b, 0x1d, 0x56, 0x25, 0x68, 0xf7, 0x14, 0xff, 0xf7, 0xe1, 0xfc, 0x87, 0x41, 0x5f, 0x65, 0x79, 0x1f, 0xe3, 0xc7, 0x33, 0x34, 0xf5, 0x6a, 0x9c, 0xad, 0x85, 0xea, 0xe9, 0x56, 0xe8, 0x85, 0xbd, 0x7b, 0x4a, 0xb, 0x41, 0x62, 0xbc, 0xa4, 0x21, 0xad, 0xed, 0xa3, 0x6d, 0x69, 0x6d, 0x1e, 0x2d, 0xbe, 0x9c, 0xbc, 0xbd, 0xd7, 0x72, 0xdd, 0x6e, 0x34, 0xfb, 0x2c, 0xef, 0x24, 0x3, 0x7f, 0xaf, 0x13, 0xc2, 0x48, 0x45, 0xaa, 0xcb, 0x97, 0x72, 0x2d, 0x85, 0x86, 0x5a, 0x8f, 0x72, 0x41, 0x91, 0x4a, 0xac, 0x8f, 0xa6, 0xe5, 0xb5, 0x53, 0x53, 0xb8, 0xde, 0x98, 0x24, 0x0, 0x6e, 0xe8, 0x2a, 0xe, 0x3b, 0xf9, 0x35, 0x88, 0x6f, 0x76, 0x20, 0x9e, 0x8a, 0x20, 0x53, 0x69, 0xda, 0x0, 0x69, 0x96, 0x12, 0x7d, 0x20, 0xbf, 0xe4, 0xe8, 0x63, 0xc6, 0xd1, 0xa9, 0xa8, 0xde, 0xe3, 0x5e, 0x30, 0xa3, 0xd1, 0x64, 0x7, 0xd8, 0x7f, 0x59, 0x96, 0x2e, 0xd1, 0xa7, 0xb2, 0x21, 0xb9, 0x3, 0xee, 0x70, 0x3f, 0x93, 0xd9, 0xa9, 0x64, 0x1f, 0xd4, 0x78, 0x7, 0x14, 0xcc, 0x51, 0xc0, 0x2d, 0xe8, 0x72, 0xc3, 0xc8, 0x3d, 0x9a, 0x19, 0xc7, 0xb3, 0xb6, 0x87, 0x42, 0x50, 0x3b, 0x40, 0xf6, 0x1, 0x9c, 0x3a, 0xd, 0xcd, 0x2d, 0xa, 0x9a, 0x77, 0x74, 0xa2, 0xea, 0x1b, 0x67, 0x36, 0x3b, 0x1a, 0x36, 0xba, 0x45, 0x73, 0x9e, 0x8e, 0x62, 0x5a, 0xf4, 0xc5, 0x7e, 0x49, 0x23, 0x3c, 0x5e, 0x18, 0xf5, 0x72, 0x24, 0xbb, 0x76, 0xad, 0x66, 0x52, 0x23, 0xf6, 0xde, 0x1b, 0x47, 0xaa, 0x56, 0xe5, 0x7d, 0x2, 0x3a, 0x54, 0x68, 0xa9, 0xd9, 0x6a, 0x87, 0xed, 0x19, 0x7a, 0xde, 0x97, 0x20, 0x4f, 0xb, 0x3f, 0x96, 0x32, 0x2f, 0x18, 0x82, 0xba, 0x4f, 0xfa, 0xda, 0x1c, 0x9f, 0xe5, 0x94, 0x1b, 0x74, 0x1b, 0x8c, 0x41, 0xae, 0xf2, 0x9f, 0xd, 0x61, 0xb7, 0x4f, 0x8c, 0xd8, 0x12, 0x48, 0x86, 0x6c, 0xf2, 0x92, 0xe6, 0x7a, 0x1d, 0x10, 0x6c, 0x42, 0xa6, 0x14, 0x59, 0xf8, 0x25, 0x29, 0x4d, 0x63, 0x72, 0xe3, 0x53, 0x4e, 0xd6, 0xb6, 0xb, 0x80, 0xf1, 0xc4, 0xde, 0xd2, 0x71, 0x58, 0xf2, 0x8c, 0xe6, 0x1b, 0xce, 0xb3, 0x74, 0xe4, 0x1e, 0x0, 0xb1, 0xc2, 0xb1, 0xfb, 0x8f, 0x72, 0x40, 0xdb, 0xa3, 0xa2, 0x90, 0xc8, 0xd2, 0xdd, 0x88, 0x45, 0xbc, 0xd5, 0x1, 0xd7, 0xce, 0xde, 0xf6, 0xda, 0xaa, 0x35, 0x21, 0xb1, 0x5f, 0xc5, 0x7d, 0xb3, 0xe2, 0xfd, 0x4a, 0xc7, 0x46, 0x3e, 0xd4, 0xce, 0xda, 0xed, 0x4d, 0x1b, 0x5a, 0x70, 0xd5, 0xd2, 0xd0, 0x57, 0x40, 0x2f, 0x92, 0xce, 0xb3, 0xd3, 0x53, 0x13, 0x98, 0x80, 0x44, 0xf5, 0x76, 0x75, 0x75, 0xc, 0xae, 0xd7, 0x28, 0xd3, 0x81, 0xa6, 0x2a, 0x9f, 0xa5, 0x6f, 0xaa, 0x2e, 0x8c, 0xdb, 0xf9, 0xd8, 0xa9, 0x57, 0xea, 0xc7, 0x7b, 0x85, 0xd6, 0x31, 0x3b, 0x84, 0x36, 0xb4, 0x32, 0x92, 0xbb, 0x4c, 0x79, 0x91, 0x2d, 0x97, 0x9, 0xb1, 0x1e, 0x20, 0x82, 0xd, 0x63, 0x5d, 0xf0, 0xb9, 0x92, 0xc4, 0x9d, 0xd2, 0x78, 0xfb, 0xf8, 0xcd, 0xcd, 0xa5, 0x84, 0xfb, 0x6a, 0xa7, 0xf8, 0xd9, 0xeb, 0xa6, 0xc6, 0x2e, 0x29, 0x23, 0x3e, 0xe9, 0xb, 0x16, 0x70, 0x15, 0x86, 0x5, 0x49, 0x8b, 0x8c, 0xe9, 0x47, 0xb0, 0x22, 0xe4, 0x5e, 0xe1, 0xc2, 0x24, 0x22, 0xf2, 0xce, 0x28, 0x5a, 0x61, 0xa6, 0xed, 0xae, 0x6e, 0x7, 0x98, 0x73, 0xe6, 0xb9, 0xd7, 0x34, 0xe6, 0x2b, 0xd7, 0xd7, 0x63, 0x39, 0x66, 0x62, 0xa, 0xde, 0x30, 0x90, 0xc3, 0xaa, 0x3d, 0xa1, 0x20, 0xf9, 0xd, 0xf4, 0xd8, 0xb3, 0x68, 0xb3, 0x86, 0x2c, 0x7f, 0x49, 0xf8, 0x87, 0x84, 0xc0, 0xcf, 0x7f, 0xdf, 0xfe, 0x16, 0x7b, 0x3, 0x5b, 0xc8, 0x60, 0x8, 0xb7, 0x4f, 0xc0, 0x1a, 0x10, 0x87, 0x26, 0xf1, 0xc0, 0x14, 0xf0, 0x0, 0x94, 0xe5, 0x30, 0x6b, 0x50, 0xee, 0xe, 0xa7, 0x74, 0x2d, 0xd, 0x84, 0xf4, 0xa3, 0x33, 0x54, 0x4a, 0x3, 0x1c, 0x53, 0xbb, 0xcb, 0x45, 0x13, 0x1f, 0xd9, 0xd2, 0x29, 0xa6, 0xe8, 0xcb, 0x57, 0xdf, 0xc, 0x81, 0x75, 0xa, 0xc2, 0x61, 0xb0, 0xde, 0x32, 0x69, 0x75, 0x86, 0x35, 0xfb, 0x14, 0xd, 0x2e, 0xc8, 0x3a, 0x27, 0x4c, 0xd8, 0x97, 0x91, 0x81, 0xdf, 0x26, 0x5b, 0xd0, 0x24, 0x39, 0xc9, 0x92, 0x8c, 0x9, 0x52, 0xb6, 0x9c, 0x63, 0x6f, 0x32, 0x19, 0xfb, 0xe6, 0x6f, 0x1c, 0x4c, 0x86, 0x5d, 0x4c, 0x62, 0x43, 0x64, 0x97, 0xa4, 0x97, 0xed, 0xb0, 0x93, 0x29, 0xcf, 0x44, 0xc4, 0x7e, 0xc, 0xcf, 0x79, 0x4d, 0xda, 0xab, 0xc5, 0x62, 0xd1, 0x4b, 0xfa, 0x2b, 0x5d, 0xae, 0x12, 0xf1, 0xc7, 0x4f, 0xc5, 0xb4, 0xf6, 0x26, 0x56, 0x2, 0xf6, 0xd7, 0x4a, 0x7a, 0x86, 0x58, 0x97, 0x46, 0xdb, 0xca, 0xdf, 0x7b, 0x4d, 0x7e, 0xdd, 0xac, 0x69, 0x4c, 0xf9, 0xed, 0x5e, 0xb, 0x72, 0x78, 0x74, 0xe8, 0x1f, 0xfe, 0xeb, 0x67, 0x7f, 0x32, 0x3e, 0x7a, 0xc8, 0x82, 0xd8, 0x6c, 0xfb, 0x2e, 0xc8, 0x9e, 0x3c, 0x7f, 0xf3, 0x82, 0xec, 0xd6, 0xaa, 0x67, 0x41, 0x8c, 0xdb, 0x38, 0x8e, 0xba, 0xa3, 0x1b, 0x60, 0x61, 0x48, 0x53, 0xca, 0x25, 0x93, 0x39, 0xcb, 0xc0, 0x9, 0x13, 0x9a, 0x92, 0x13, 0x70, 0x44, 0xe1, 0x84, 0x29, 0xb9, 0x46, 0xf2, 0xb7, 0x27, 0x2, 0xc1, 0x30, 0xf8, 0x43, 0xdc, 0xf2, 0x4a, 0x27, 0xf5, 0x8d, 0x53, 0xf, 0x1b, 0x2f, 0x7b, 0xa8, 0xa8, 0xf0, 0x99, 0xe0, 0xf8, 0xd1, 0x59, 0x46, 0xbc, 0xe2, 0x22, 0x18, 0xe3, 0xf8, 0x45, 0x53, 0xc, 0x11, 0x25, 0xc5, 0x49, 0x9f, 0x8f, 0x60, 0xdc, 0xbc, 0xfa, 0x21, 0x3, 0x2f, 0x8c, 0x96, 0x5d, 0xf2, 0xc9, 0x50, 0x9c, 0x6f, 0x27, 0x6e, 0xad, 0x15, 0xb2, 0xda, 0xac, 0xdb, 0x5c, 0x62, 0xb0, 0xce, 0xf4, 0x63, 0xc5, 0x14, 0x86, 0xd2, 0x6c, 0x28, 0xdf, 0x14, 0x2b, 0xb0, 0xaa, 0xfd, 0x20, 0xb2, 0xb2, 0x38, 0x1c, 0x8a, 0x60, 0x59, 0xef, 0x4b, 0xa9, 0x86, 0x6f, 0xa0, 0xbf, 0xfa, 0xae, 0xdb, 0xd1, 0x3e, 0x81, 0x93, 0x0, 0x62, 0xac, 0x8, 0x87, 0x32, 0x71, 0x87, 0x57, 0x30, 0x2a, 0xfb, 0xfb, 0x47, 0xe3, 0xf1, 0x58, 0x3e, 0xd7, 0x5, 0x63, 0x22, 0x72, 0x25, 0xf2, 0x3f, 0x74, 0x54, 0xc8, 0xb7, 0x76, 0xc4, 0x97, 0x49, 0xc7, 0x75, 0xb2, 0x2e, 0x4c, 0xe4, 0x46, 0xc2, 0x94, 0x97, 0x6e, 0x95, 0x6b, 0x11, 0x95, 0x6e, 0x90, 0x20, 0x67, 0x82, 0x3b, 0xe5, 0xef, 0xd5, 0x49, 0xae, 0xf3, 0x75, 0x22, 0xce, 0xa8, 0x2c, 0xff, 0xc4, 0xb2, 0x1c, 0x2f, 0xb1, 0xea, 0x52, 0x55, 0x19, 0xcb, 0xf, 0xa6, 0x1b, 0xad, 0xfa, 0x66, 0xf5, 0x82, 0xc1, 0x28, 0xdf, 0x59, 0x11, 0x3c, 0xa7, 0x22, 0xcd, 0x4a, 0xa1, 0x14, 0xee, 0x48, 0xe9, 0xe6, 0x68, 0xab, 0x9, 0xed, 0x79, 0x52, 0xde, 0x50, 0xe6, 0x51, 0xea, 0x80, 0x87, 0xe9, 0x66, 0x1, 0x9, 0xa2, 0xd, 0x83, 0x73, 0xf7, 0x2, 0x33, 0x71, 0x72, 0xe, 0x6b, 0xcf, 0xa2, 0x15, 0x4e, 0xd7, 0x6b, 0x53, 0x7a, 0xd1, 0x2b, 0xfb, 0xe9, 0x4, 0x59, 0xe7, 0x8d, 0xcf, 0x68, 0xbe, 0x9a, 0xb6, 0x7c, 0x45, 0xb, 0xa3, 0xa2, 0x4a, 0xb2, 0x14, 0x49, 0x23, 0x27, 0xab, 0xaf, 0x6d, 0x8f, 0x75, 0xeb, 0xef, 0xc7, 0xe8, 0x7c, 0xb7, 0xac, 0xc1, 0x9e, 0xc9, 0xca, 0x7b, 0xbf, 0x2d, 0xd6, 0x78, 0x45, 0xc9, 0xc6, 0xc8, 0xaf, 0xe3, 0x92, 0x60, 0xff, 0x57, 0xa0, 0xec, 0xad, 0x67, 0x9e, 0x54, 0xe8, 0xe7, 0xff, 0xf2, 0x61, 0x45, 0xb9, 0x82, 0x3a, 0xea, 0x36, 0x1b, 0xa4, 0xed, 0x5a, 0x4d, 0x72, 0x94, 0x65, 0xe2, 0xff, 0x1, 0x8e, 0x80, 0xd0, 0xef, 0x98, 0x27, 0x0, 0x0, 0x0, 0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0xed, 0x7d, 0x69, 0x77, 0xdb, 0x46, 0xb2, 0xe8, 0xe7, 0x37, 0xbf, 0x42, 0xc2, 0x24, 0xa, 0x20, 0x36, 0x29, 0x52, 0x19, 0xe7, 0xce, 0x5, 0x5, 0xf1, 0xd8, 0x8e, 0x33, 0xc9, 0x4c, 0x16, 0x8f, 0xed, 0x4c, 0x16, 0x59, 0xc9, 0x1, 0x81, 0x26, 0x9, 0x9b, 0x2, 0x18, 0x2, 0x94, 0x25, 0x4b, 0x7c, 0xbf, 0xfd, 0x55, 0x55, 0x2f, 0xe8, 0x6, 0x1a, 0x94, 0xec, 0x64, 0x96, 0xfb, 0x6e, 0xce, 0x4c, 0x2c, 0xb0, 0xf7, 0xa5, 0xba, 0xb6, 0xae, 0xaa, 0x3e, 0x3a, 0xfa, 0xf1, 0xc9, 0xd3, 0x17, 0xdf, 0xfc, 0xe1, 0x32, 0x5e, 0xef, 0xfd, 0xc8, 0x57, 0x55, 0x11, 0xcd, 0x36, 0x79, 0x52, 0x65, 0x45, 0xee, 0x7, 0x37, 0xea, 0x73, 0xef, 0x33, 0x3f, 0xe, 0x6e, 0xd6, 0xbc, 0xda, 0xac, 0xf3, 0xbd, 0x7c, 0xb3, 0x5c, 0x46, 0x51, 0x3c, 0x79, 0x5e, 0xad, 0xb3, 0x7c, 0xe, 0x19, 0xe1, 0xd5, 0xd9, 0xf5, 0x20, 0x89, 0x97, 0x4b, 0xf8, 0x3e, 0xbf, 0xbd, 0xf5, 0x8a, 0xe9, 0x2b, 0x9e, 0x54, 0xde, 0x56, 0xd7, 0xfe, 0x4b, 0x5d, 0xdb, 0x53, 0x89, 0x5e, 0x14, 0x61, 0xa3, 0x75, 0xa1, 0xcf, 0x1b, 0x5d, 0xec, 0x47, 0xf1, 0xc1, 0x41, 0xc, 0x1d, 0xd, 0xde, 0x64, 0x79, 0x5a, 0xbc, 0xa9, 0x4b, 0x7e, 0xe1, 0x2c, 0x39, 0xc8, 0x8b, 0x94, 0xbf, 0xb8, 0x5e, 0x71, 0xac, 0xf2, 0xe9, 0x37, 0x8f, 0xbf, 0xfd, 0xea, 0xc9, 0xd7, 0x2f, 0x7e, 0xfe, 0xfa, 0x9b, 0x4f, 0x9f, 0xd4, 0x35, 0xff, 0x6a, 0xc, 0x44, 0x8e, 0xb2, 0x39, 0x8c, 0xbf, 0x19, 0x8d, 0x63, 0xf1, 0x83, 0x83, 0xfd, 0xcf, 0xe9, 0xcf, 0x37, 0x54, 0x7e, 0x30, 0xe7, 0xd5, 0xd3, 0x75, 0x51, 0x15, 0x15, 0xf4, 0xf4, 0xcd, 0xc, 0x72, 0xa2, 0x48, 0xe6, 0xac, 0x54, 0x72, 0xdd, 0xd8, 0x97, 0x46, 0x7f, 0xf9, 0xe6, 0x62, 0xca, 0xd7, 0xd0, 0x1f, 0x16, 0x29, 0x66, 0x7b, 0xf1, 0x60, 0xc9, 0xf3, 0x79, 0xb5, 0xa8, 0x4b, 0x7f, 0x65, 0x74, 0x3d, 0x97, 0xb, 0xca, 0xf4, 0x6e, 0xb4, 0xe6, 0xbc, 0x35, 0x46, 0xfd, 0xb5, 0x91, 0xad, 0x1a, 0x3e, 0x1d, 0x4e, 0x92, 0xc1, 0x2c, 0x1f, 0x24, 0x45, 0x9e, 0xc4, 0xd5, 0x20, 0x5e, 0xad, 0x96, 0xd7, 0xfe, 0xd9, 0x39, 0x83, 0xd, 0x8b, 0xeb, 0x9a, 0xdf, 0x58, 0x35, 0xd7, 0x7c, 0xb5, 0x8c, 0x13, 0xee, 0x1f, 0x85, 0xe1, 0xd1, 0x9c, 0x79, 0x47, 0x5e, 0x50, 0x27, 0xf9, 0x67, 0xf, 0xfb, 0x3f, 0x9e, 0xf7, 0x2, 0xf1, 0xf7, 0x2c, 0xee, 0xbf, 0x3d, 0xf, 0xb0, 0xd0, 0x7, 0xa3, 0x9f, 0x3f, 0x38, 0xb6, 0xb, 0x42, 0xde, 0xcb, 0xf4, 0x5c, 0x96, 0x74, 0x17, 0xfa, 0x19, 0x53, 0xfb, 0x90, 0x52, 0x15, 0x5f, 0x16, 0x6f, 0xf8, 0xfa, 0x71, 0x5c, 0x72, 0xdf, 0x98, 0xd1, 0x53, 0x73, 0x5c, 0x7b, 0x59, 0xbe, 0xf7, 0x6a, 0xf2, 0xea, 0x2c, 0x3e, 0xf, 0xf1, 0x9f, 0x28, 0xe7, 0x6f, 0xf6, 0x9e, 0xf1, 0xf9, 0x93, 0xab, 0x95, 0xef, 0xf9, 0x3f, 0xdd, 0xbe, 0x7c, 0x59, 0x6, 0x5e, 0x2f, 0xee, 0x79, 0x3e, 0x7c, 0xdd, 0x7e, 0x10, 0x78, 0x46, 0x3b, 0x7f, 0x87, 0x35, 0x9c, 0x36, 0x37, 0x61, 0x5f, 0x6d, 0xc2, 0xf4, 0xf6, 0xf6, 0xf5, 0x19, 0x2e, 0xc1, 0xf9, 0x64, 0x1a, 0x4e, 0x7b, 0xde, 0xea, 0xca, 0x0, 0xdb, 0x67, 0x38, 0x4, 0x3c, 0x17, 0x53, 0x96, 0x8c, 0xe5, 0x50, 0x32, 0xe8, 0xfe, 0xf6, 0xd6, 0x9f, 0x46, 0x8b, 0x41, 0xb2, 0xe6, 0x71, 0xc5, 0x9f, 0x2c, 0xf9, 0x5, 0xcf, 0x2b, 0x28, 0xca, 0x16, 0x83, 0x69, 0x91, 0x5e, 0xe3, 0x42, 0xf3, 0x3c, 0x7d, 0xbc, 0xc8, 0x96, 0xa9, 0x3f, 0xd, 0x58, 0x12, 0x1, 0xc8, 0x3c, 0x2e, 0x2e, 0x56, 0x9b, 0x8a, 0xa7, 0xcf, 0xab, 0xeb, 0x25, 0xf7, 0xa7, 0xcc, 0x83, 0x89, 0xb, 0x48, 0x5a, 0xf1, 0x75, 0x75, 0xfd, 0x8f, 0x78, 0xb9, 0xe1, 0xbe, 0x97, 0x66, 0x25, 0xac, 0xce, 0xb5, 0x17, 0xb0, 0xe9, 0x60, 0x15, 0xaf, 0xa1, 0xd9, 0xaf, 0x1, 0xa6, 0x61, 0xcd, 0x2e, 0x8a, 0x4b, 0xae, 0x1b, 0xf4, 0xf2, 0x22, 0xe7, 0x0, 0x47, 0xc9, 0xc1, 0x81, 0x9f, 0x44, 0xde, 0x74, 0x59, 0x24, 0xaf, 0xa1, 0xa, 0x8e, 0x2c, 0x4a, 0xc4, 0xdf, 0x7a, 0xe, 0xcf, 0xd, 0x8, 0x4c, 0xb0, 0x5, 0x68, 0xd5, 0x83, 0xd5, 0x8c, 0x27, 0x33, 0x9, 0x61, 0x3, 0x95, 0x1c, 0x84, 0xc9, 0xe0, 0x22, 0x5e, 0xa9, 0x14, 0xec, 0xba, 0x74, 0x81, 0xdf, 0x8, 0xf, 0x98, 0x3a, 0x6c, 0x93, 0x38, 0xbc, 0x2c, 0xb2, 0x74, 0x6f, 0x68, 0x42, 0xe3, 0xb, 0x3f, 0x61, 0x29, 0xe3, 0x80, 0x3f, 0x8a, 0xb5, 0x3f, 0xc5, 0xcd, 0x4b, 0x3, 0xe, 0xa3, 0xfd, 0x9b, 0x9f, 0x9e, 0x4d, 0xcf, 0x83, 0xdb, 0xdb, 0x27, 0xe2, 0x23, 0x98, 0xa8, 0x24, 0x38, 0x65, 0x7f, 0xf3, 0x13, 0xf1, 0x45, 0x7f, 0xa3, 0x9b, 0x6d, 0xc0, 0x9e, 0xe8, 0xcc, 0x27, 0x76, 0xe6, 0xd9, 0x79, 0xc0, 0x5e, 0xd0, 0x27, 0xc3, 0x12, 0xd0, 0x55, 0x10, 0xe2, 0xc7, 0x7e, 0x84, 0xa8, 0x40, 0x94, 0xa1, 0xaa, 0xf5, 0x98, 0xbe, 0x35, 0xe1, 0x40, 0xe2, 0xb0, 0xe9, 0x24, 0x41, 0xf4, 0x85, 0xff, 0xc, 0x66, 0xd9, 0xb2, 0xe2, 0x30, 0x5a, 0xa3, 0xca, 0x3f, 0xb0, 0xa, 0x83, 0xa9, 0xe8, 0x6a, 0x7f, 0x81, 0xfc, 0xc9, 0x54, 0x1d, 0x4d, 0xcc, 0x9, 0xa7, 0x75, 0xf9, 0xef, 0x44, 0xf9, 0xe0, 0x46, 0xb4, 0x9e, 0x4c, 0x62, 0xb9, 0x75, 0xf, 0x2b, 0x40, 0x95, 0x53, 0xd8, 0x7f, 0xa8, 0x1e, 0xc6, 0x83, 0x92, 0x57, 0x46, 0xa, 0x54, 0xa8, 0x9b, 0xf8, 0x9e, 0x7e, 0x13, 0xd0, 0xa5, 0x11, 0x74, 0xb4, 0x8c, 0xcb, 0xf2, 0xeb, 0xf8, 0x82, 0x3, 0x56, 0xf5, 0x18, 0x8f, 0xd2, 0x83, 0x83, 0x74, 0x30, 0x85, 0x93, 0x2, 0x0, 0x83, 0x73, 0x55, 0x50, 0x99, 0x44, 0x88, 0x90, 0xf9, 0x44, 0x67, 0x86, 0x69, 0xe8, 0x1b, 0x3f, 0xa3, 0x24, 0x34, 0x1a, 0x8b, 0x12, 0x26, 0xf6, 0xcc, 0xe8, 0xf8, 0x7, 0xdc, 0xe0, 0x6a, 0x7d, 0xad, 0x8f, 0xdc, 0xc4, 0xab, 0xd6, 0x1b, 0x4, 0xb3, 0x18, 0xc0, 0xdd, 0x9b, 0xc5, 0xcb, 0x92, 0x7e, 0x4c, 0xf6, 0x47, 0xa1, 0x87, 0xf3, 0xa3, 0x1f, 0xf8, 0x11, 0xe2, 0xc1, 0xa3, 0x5f, 0xbd, 0x38, 0x3c, 0xfa, 0xe9, 0xec, 0xe5, 0xd9, 0xcb, 0x9b, 0xf3, 0xa3, 0x41, 0xc5, 0x4b, 0x3c, 0x14, 0x80, 0x82, 0x0, 0x92, 0x4b, 0xfe, 0xd7, 0xe7, 0xdf, 0x20, 0x8e, 0xa, 0x9, 0xf9, 0x0, 0x3a, 0x4a, 0x16, 0x7e, 0xbd, 0x1b, 0xf1, 0xb6, 0x1e, 0xc8, 0x8f, 0x62, 0x9f, 0xa6, 0x50, 0x78, 0x8c, 0xe0, 0x83, 0x4b, 0x91, 0x44, 0x43, 0x96, 0x46, 0x26, 0x5c, 0x4a, 0x14, 0x37, 0x4e, 0x4f, 0x93, 0x71, 0xd2, 0xeb, 0x5, 0x3f, 0x5a, 0x50, 0x7b, 0x96, 0x9c, 0x43, 0x1b, 0x5b, 0xac, 0x2a, 0x77, 0x90, 0x3d, 0x64, 0x8f, 0x60, 0xfd, 0x0, 0xfb, 0xcd, 0x22, 0x3e, 0x28, 0x97, 0x59, 0xc2, 0xd9, 0x1c, 0xbe, 0xc4, 0xae, 0xb3, 0x45, 0x24, 0x68, 0xcc, 0x20, 0x2d, 0x92, 0xd, 0x1e, 0x67, 0x96, 0x1, 0x0, 0xb2, 0x57, 0xf8, 0xcf, 0xeb, 0xe8, 0xc6, 0x4b, 0x8a, 0xe5, 0xe6, 0x22, 0xef, 0x27, 0xc5, 0x26, 0xaf, 0xbc, 0x70, 0xc4, 0xc4, 0xef, 0x12, 0xbe, 0xbc, 0x59, 0x91, 0x57, 0xfd, 0x37, 0x3c, 0x9b, 0x2f, 0x28, 0xc7, 0x5b, 0x66, 0x39, 0xef, 0x2f, 0xf4, 0xef, 0x62, 0x15, 0x27, 0x59, 0x75, 0x8d, 0x39, 0x6f, 0xfb, 0xd0, 0x7, 0xbf, 0xc2, 0xd4, 0xb7, 0x45, 0x71, 0x11, 0x8e, 0xb6, 0x6c, 0x19, 0x1d, 0xfd, 0xf4, 0xb2, 0x3c, 0x3c, 0xf1, 0x5f, 0xbe, 0xe9, 0xdd, 0xee, 0x7, 0x67, 0x3f, 0x9d, 0x9e, 0x1f, 0x9e, 0x1e, 0xb1, 0xb, 0x48, 0xa6, 0xb4, 0x0, 0x32, 0x5f, 0x1e, 0x4d, 0x4e, 0xfd, 0x49, 0x78, 0xf2, 0xf2, 0xe8, 0xe5, 0xe8, 0xf4, 0x36, 0xf8, 0xe0, 0x88, 0xe5, 0xd1, 0xd1, 0x89, 0x3f, 0xd9, 0x7, 0x4, 0x11, 0xdf, 0x4e, 0xd7, 0xb7, 0x30, 0x98, 0x5b, 0xe, 0x68, 0x2d, 0xbd, 0x5d, 0xac, 0x6f, 0xb3, 0x8b, 0xf9, 0x6d, 0x96, 0x3, 0xae, 0xb9, 0x85, 0x81, 0xbc, 0xbe, 0xbd, 0xe0, 0x55, 0x7c, 0xb, 0x1b, 0x10, 0x5f, 0x4, 0xbe, 0x7f, 0xf6, 0xf2, 0x4d, 0x8, 0xf8, 0x9b, 0x7a, 0x9, 0x5e, 0x1e, 0x9d, 0x1e, 0xcd, 0x33, 0x56, 0x40, 0x57, 0xd0, 0x3a, 0x22, 0xae, 0xdb, 0x45, 0x75, 0xb1, 0x84, 0xf6, 0x33, 0xb6, 0x8a, 0x8e, 0x6a, 0xd4, 0xfd, 0x4b, 0x74, 0xe6, 0x5d, 0xc6, 0x4b, 0x8f, 0x79, 0x49, 0x59, 0xc2, 0xbf, 0x58, 0xa, 0xfe, 0x54, 0xfc, 0xaa, 0x82, 0x3f, 0x69, 0x5c, 0xc5, 0xf0, 0xe7, 0x4d, 0x96, 0x56, 0xb, 0xcc, 0x14, 0x13, 0x67, 0x5e, 0x31, 0x9b, 0x1, 0x98, 0x7b, 0xe7, 0x6c, 0xd, 0xd5, 0xe3, 0x19, 0x2c, 0x32, 0x24, 0xae, 0x0, 0xfb, 0x3, 0x6a, 0x84, 0xaf, 0x29, 0x87, 0xbd, 0xe5, 0xf0, 0x21, 0x90, 0x25, 0x94, 0x2b, 0x5b, 0x18, 0xd5, 0xab, 0xe2, 0xe9, 0x92, 0x3, 0x66, 0xab, 0x1c, 0x59, 0x6b, 0x48, 0xdf, 0x44, 0x0, 0xb1, 0x61, 0x3b, 0xf, 0x27, 0x83, 0xd5, 0xf0, 0x6f, 0x58, 0xb2, 0x6a, 0xc1, 0xe3, 0x14, 0xff, 0xce, 0x8a, 0xa2, 0xc2, 0xbf, 0x69, 0x58, 0x41, 0x22, 0xfc, 0xe3, 0x1d, 0x7a, 0xed, 0xea, 0x69, 0x76, 0x9, 0xf4, 0x83, 0x5d, 0x46, 0x47, 0x9, 0x20, 0xed, 0x25, 0xaf, 0xf8, 0xed, 0xb2, 0x88, 0x53, 0x58, 0xde, 0x2c, 0x87, 0x69, 0xc4, 0x0, 0xa6, 0x97, 0xfc, 0x88, 0xbd, 0x89, 0x10, 0xd6, 0xdf, 0xf4, 0xcf, 0xf, 0x61, 0x47, 0xae, 0x10, 0x50, 0xae, 0xa3, 0x2b, 0x20, 0x66, 0x82, 0x2b, 0x62, 0x6f, 0x31, 0xe5, 0x71, 0xe4, 0x6e, 0x9d, 0x7d, 0xa, 0x23, 0x8f, 0xa7, 0x4, 0xe, 0x21, 0x4e, 0xf3, 0xb, 0x2, 0xc, 0x6, 0x45, 0xd3, 0x22, 0x5f, 0x5e, 0x87, 0x1e, 0x7e, 0x7d, 0x3, 0x5f, 0x1e, 0x2, 0xd8, 0xda, 0xb, 0x69, 0xd5, 0x3f, 0x2b, 0x70, 0x11, 0xe9, 0x18, 0x43, 0x8a, 0x3e, 0xce, 0x1e, 0xbb, 0x88, 0xaf, 0xc4, 0x79, 0x8, 0x3d, 0xf8, 0xfc, 0x92, 0x3e, 0x3d, 0x96, 0xf0, 0xe5, 0xb2, 0x44, 0xf0, 0xcb, 0xe7, 0x50, 0x1a, 0x7e, 0x3c, 0x17, 0x3f, 0x44, 0xce, 0x2a, 0x4e, 0x53, 0x9d, 0xf3, 0x54, 0xfc, 0x80, 0x11, 0x14, 0x6f, 0xa0, 0x4a, 0xe, 0x3, 0x28, 0xde, 0x40, 0xf1, 0xdc, 0x43, 0x50, 0x17, 0x29, 0xf0, 0x21, 0x52, 0x36, 0x25, 0x7, 0x32, 0x11, 0x7a, 0xf0, 0xf7, 0xab, 0x78, 0xe5, 0xb1, 0x19, 0x40, 0x17, 0x9f, 0x16, 0xeb, 0x94, 0xaf, 0x43, 0x8f, 0x7e, 0x3c, 0xa2, 0x1f, 0x58, 0x17, 0x56, 0xc, 0xfe, 0x9f, 0x66, 0xb4, 0x95, 0xd8, 0x6, 0x25, 0x3c, 0x91, 0x9, 0xde, 0x96, 0x3d, 0x89, 0x1e, 0xae, 0xd7, 0xf1, 0xf5, 0x20, 0x2b, 0xe9, 0xef, 0xed, 0xad, 0x83, 0xe0, 0x20, 0xf9, 0x2f, 0xab, 0x38, 0x4f, 0x90, 0x62, 0x53, 0xb1, 0xad, 0x42, 0x7c, 0x6f, 0x81, 0x62, 0x1, 0x2e, 0xe1, 0x65, 0xcd, 0xb5, 0x12, 0xfa, 0xc8, 0x66, 0xfe, 0x3e, 0xd0, 0xf6, 0x7d, 0x40, 0x5e, 0xa3, 0x7d, 0x93, 0x5e, 0x5, 0xa2, 0xe2, 0xfe, 0x68, 0x2c, 0x10, 0xb, 0x70, 0x97, 0x7c, 0xfa, 0x3a, 0xab, 0xbe, 0x12, 0xcd, 0x3c, 0xe7, 0x4b, 0x60, 0xe5, 0x8a, 0xf5, 0xed, 0x6d, 0x3c, 0xb8, 0x28, 0xde, 0x3a, 0x52, 0xb, 0x57, 0x49, 0x3b, 0x69, 0xc, 0xbd, 0x27, 0x81, 0x42, 0xcd, 0x8a, 0x5a, 0x4c, 0x3, 0xea, 0x12, 0xe8, 0x22, 0x74, 0x5a, 0x53, 0x77, 0x40, 0x48, 0xfb, 0x5c, 0x4d, 0x67, 0x6, 0xc4, 0x8b, 0x47, 0x8f, 0x3, 0x8b, 0x87, 0x0, 0xce, 0x22, 0x8d, 0xfe, 0xef, 0xdb, 0xc1, 0x2f, 0x65, 0xec, 0x73, 0x68, 0x66, 0x40, 0x70, 0x43, 0xbc, 0x27, 0x83, 0xa, 0x8f, 0x2d, 0xfe, 0x0, 0xb, 0x6f, 0xd9, 0xc3, 0xc8, 0xb5, 0x8c, 0x35, 0xf3, 0xd5, 0xef, 0xf9, 0x83, 0x60, 0x2, 0x87, 0xdb, 0x5e, 0x35, 0x59, 0x70, 0xa, 0x24, 0xae, 0x2a, 0xbe, 0x85, 0x21, 0x48, 0xae, 0x2c, 0xf4, 0x3c, 0x20, 0xef, 0xec, 0x91, 0xab, 0xd5, 0x36, 0xa3, 0x4a, 0x14, 0x4c, 0xf7, 0xa9, 0x6, 0x3b, 0x5, 0x46, 0x39, 0xc1, 0x56, 0xde, 0xe, 0x0, 0x46, 0xe6, 0x78, 0x1a, 0x22, 0xa3, 0xa, 0xb1, 0xb, 0xb8, 0x3e, 0x73, 0x96, 0xb1, 0x57, 0x6a, 0x3d, 0x2e, 0x4, 0x19, 0x99, 0x22, 0xe1, 0x9f, 0x47, 0x89, 0xdf, 0x3c, 0x4e, 0x82, 0x7, 0x1c, 0x7c, 0x30, 0xa, 0x82, 0x80, 0xcd, 0x91, 0x2f, 0x53, 0x73, 0x84, 0xa, 0xd3, 0x48, 0xff, 0xf2, 0x73, 0xe6, 0x9d, 0x7c, 0x30, 0x3a, 0x3d, 0x39, 0xfa, 0xe0, 0xf8, 0xd4, 0xb, 0x70, 0x41, 0x5, 0xa7, 0x90, 0x46, 0xcb, 0xba, 0x8b, 0xba, 0x35, 0x96, 0x22, 0xd3, 0xb2, 0x81, 0x6, 0xd3, 0x8, 0x90, 0x44, 0x0, 0x94, 0x60, 0x73, 0x96, 0x9e, 0xb3, 0x57, 0x30, 0x9d, 0x9c, 0xaf, 0x3f, 0x7f, 0xf1, 0xd5, 0x97, 0x91, 0xe7, 0xf5, 0xa6, 0x40, 0x43, 0x92, 0x1, 0x8f, 0x81, 0x98, 0x49, 0x6e, 0xea, 0x95, 0x41, 0x85, 0x2, 0x66, 0x48, 0x52, 0xaf, 0xac, 0x5d, 0xaa, 0x16, 0x59, 0x19, 0x6c, 0x61, 0x1c, 0x7f, 0xf3, 0x39, 0xce, 0x2d, 0x83, 0xb9, 0xcd, 0x81, 0x55, 0x14, 0x6d, 0xf1, 0xc6, 0xb6, 0xfc, 0x62, 0xec, 0xf8, 0x69, 0x7f, 0x34, 0x41, 0xe, 0xf, 0x39, 0x89, 0x6c, 0x10, 0x3, 0x1b, 0x41, 0x65, 0xb0, 0xad, 0x39, 0xae, 0xed, 0x8f, 0x91, 0x73, 0x4b, 0x63, 0x24, 0xe3, 0xc8, 0xfb, 0xf, 0x7e, 0xfe, 0x99, 0xe4, 0x94, 0x9f, 0x7f, 0x8e, 0x50, 0x38, 0x60, 0xc8, 0x8d, 0x8, 0xa8, 0x8d, 0xa6, 0xc4, 0x64, 0xc4, 0xd8, 0x4a, 0x56, 0xfe, 0x18, 0xdd, 0x75, 0x10, 0xa1, 0x2f, 0x2a, 0x9a, 0x67, 0xf6, 0x46, 0x8a, 0x6d, 0xe4, 0x63, 0x3a, 0x82, 0x81, 0x3e, 0xa7, 0x3f, 0xfa, 0x1, 0x26, 0x79, 0x25, 0xe1, 0xc7, 0x5a, 0xc, 0x9a, 0x6, 0x90, 0x8a, 0x5b, 0x5, 0xe9, 0x17, 0x3e, 0x70, 0xb7, 0x27, 0x90, 0x37, 0x3d, 0x1b, 0x9e, 0x1f, 0x1c, 0xe8, 0xad, 0x9, 0x78, 0x54, 0x43, 0xd, 0xf4, 0xa1, 0x37, 0xa, 0x7a, 0x63, 0xd3, 0x8, 0xb9, 0x90, 0x31, 0x7, 0x6, 0x5, 0x8f, 0x7d, 0x8a, 0xc7, 0x5d, 0x1f, 0x3e, 0x3f, 0x45, 0xce, 0x2e, 0x47, 0xbe, 0x79, 0x8c, 0x8d, 0xe0, 0x19, 0x5a, 0xe0, 0x7a, 0xa9, 0xe2, 0xc8, 0xd1, 0xd5, 0xa5, 0x17, 0x28, 0xa0, 0xc4, 0xe9, 0x35, 0x16, 0x87, 0x4c, 0x5a, 0x8, 0xa3, 0xc0, 0x14, 0x13, 0x9f, 0x88, 0x1, 0x7d, 0x45, 0x4d, 0x42, 0x2b, 0x7b, 0x90, 0xf6, 0x57, 0x91, 0x86, 0xac, 0xa8, 0x31, 0x1c, 0xcc, 0xe9, 0x9a, 0x83, 0x9a, 0xee, 0x6f, 0x30, 0x95, 0xad, 0xb1, 0xc6, 0x88, 0x1f, 0xb6, 0x20, 0x72, 0x38, 0x81, 0x40, 0x6c, 0x96, 0x80, 0x17, 0x84, 0xb5, 0x2b, 0xc0, 0xc5, 0xa9, 0xb5, 0xcf, 0x52, 0xd8, 0x89, 0x94, 0x6c, 0xb0, 0x9e, 0x13, 0x37, 0x54, 0xb2, 0x51, 0x20, 0x8f, 0xa4, 0x37, 0x2d, 0x8a, 0x25, 0x8f, 0x73, 0x43, 0x8e, 0xa5, 0xa3, 0x16, 0xb3, 0x18, 0x0, 0xaa, 0x5c, 0x64, 0xb3, 0xca, 0xf, 0x10, 0x92, 0x81, 0x6c, 0x3d, 0xa1, 0x83, 0xa1, 0x9a, 0x7, 0xa4, 0xf0, 0x82, 0x98, 0x66, 0x84, 0x56, 0x1, 0x66, 0x30, 0x85, 0xc6, 0x48, 0x9, 0x29, 0xc3, 0xe9, 0xf4, 0xfe, 0x28, 0xa1, 0x0, 0xb0, 0xe5, 0x3e, 0x70, 0xbd, 0xde, 0x40, 0xfd, 0x9e, 0x47, 0xe9, 0xed, 0x2d, 0x7, 0xc, 0x45, 0x4c, 0x9c, 0x3f, 0x2, 0xe, 0x1c, 0xd9, 0x37, 0xb1, 0xcc, 0x73, 0x35, 0x4c, 0xd2, 0x11, 0x1c, 0x1c, 0x2c, 0x80, 0x5f, 0x9e, 0xf8, 0x88, 0xe5, 0x41, 0xd8, 0x92, 0x48, 0xe3, 0xd1, 0xf5, 0x17, 0x29, 0x14, 0xc, 0x26, 0xc0, 0x25, 0x86, 0x67, 0xe7, 0xa1, 0x4d, 0x1f, 0xe, 0xe, 0xfe, 0xdb, 0xfa, 0x3d, 0x81, 0x12, 0x72, 0x35, 0xa0, 0xb1, 0xfd, 0x14, 0x98, 0x6c, 0xb3, 0xb1, 0xf2, 0xd1, 0xf5, 0x63, 0x45, 0x87, 0xa1, 0xd1, 0xb0, 0x91, 0xf7, 0x22, 0x9e, 0x53, 0xe, 0xb1, 0xfd, 0xbf, 0x6c, 0xf8, 0xfa, 0x5a, 0xd1, 0x88, 0x87, 0xd0, 0x20, 0x0, 0x5, 0xee, 0x3, 0x12, 0xc5, 0x18, 0xe, 0x16, 0x30, 0xb, 0x8a, 0xfd, 0x94, 0x2d, 0xe8, 0xac, 0x89, 0xfb, 0x50, 0xc3, 0x48, 0xa7, 0xa8, 0xf9, 0x50, 0xc5, 0x50, 0x7a, 0x9, 0xed, 0xa2, 0xc8, 0x42, 0x8f, 0xa7, 0x12, 0x1b, 0xd6, 0x54, 0x27, 0x18, 0x8b, 0x63, 0x57, 0x3, 0xd8, 0xfe, 0x70, 0xac, 0x48, 0x23, 0xe, 0xa, 0x37, 0x37, 0xfa, 0xc, 0x3e, 0xb2, 0xf2, 0x33, 0xd9, 0x60, 0xf4, 0x17, 0xfa, 0xf9, 0x1d, 0x71, 0xca, 0xd1, 0xe7, 0xf4, 0x83, 0xa8, 0x71, 0xf4, 0x84, 0xbe, 0x9f, 0x2e, 0x61, 0xc, 0x42, 0x17, 0x12, 0xfd, 0x8d, 0x52, 0x9e, 0x5c, 0xac, 0xaa, 0x6b, 0x99, 0xd2, 0x2, 0xb3, 0xb1, 0x16, 0xe, 0xe3, 0x9a, 0x28, 0xab, 0xb1, 0xe0, 0x10, 0xb2, 0x5c, 0xb4, 0x6e, 0x4e, 0xc8, 0x20, 0x2d, 0x5c, 0x61, 0x45, 0xb1, 0x3b, 0x53, 0x16, 0xa3, 0x24, 0x85, 0xeb, 0x9, 0x2b, 0xbe, 0x44, 0xc2, 0x15, 0x3d, 0xc4, 0x89, 0xc0, 0x39, 0x8b, 0x3a, 0x94, 0x28, 0x28, 0xb4, 0x78, 0x5e, 0x28, 0x58, 0xb6, 0x5a, 0x7f, 0x43, 0x75, 0x94, 0x42, 0xb, 0x5b, 0xdc, 0x6c, 0xb2, 0x14, 0x44, 0x10, 0x80, 0xef, 0xcd, 0x6a, 0x55, 0xac, 0x2b, 0xe4, 0xed, 0xf0, 0xfc, 0xac, 0xd6, 0xe2, 0xb, 0xd8, 0x21, 0x27, 0x1c, 0x3, 0x22, 0x7, 0x58, 0x3e, 0x3b, 0x47, 0xb4, 0x81, 0xaa, 0xa0, 0x0, 0xa7, 0xcc, 0xa3, 0xe1, 0x98, 0x9f, 0x28, 0x25, 0xcd, 0x98, 0x83, 0xf4, 0x92, 0x44, 0x20, 0xee, 0x9c, 0x71, 0x94, 0x63, 0x99, 0x50, 0xee, 0x24, 0x28, 0xe8, 0xad, 0x36, 0xe5, 0x2, 0x8e, 0x8d, 0xc0, 0x25, 0x58, 0x75, 0x26, 0x56, 0x4b, 0x14, 0x9f, 0x81, 0x2c, 0xe3, 0x2c, 0x2e, 0x27, 0xf8, 0x35, 0x20, 0x8c, 0xad, 0x24, 0x29, 0xee, 0x53, 0xa6, 0x87, 0x45, 0x50, 0x2, 0x42, 0xd6, 0x38, 0xa9, 0xc7, 0x85, 0x52, 0x15, 0x82, 0x88, 0x5c, 0x7, 0x14, 0xa9, 0x12, 0x86, 0x7f, 0x80, 0x8e, 0x47, 0xfb, 0xa3, 0x40, 0x8b, 0x6e, 0x7a, 0x74, 0xa9, 0x18, 0x9d, 0x59, 0x9, 0x48, 0x66, 0xca, 0xf0, 0x4f, 0xa3, 0xd2, 0x58, 0xd7, 0x86, 0x1, 0xce, 0x81, 0x48, 0xbb, 0x11, 0xd6, 0xbc, 0xe6, 0x9d, 0xb6, 0x4c, 0x4a, 0x68, 0x28, 0x48, 0xa2, 0x88, 0x5f, 0x8b, 0x95, 0x11, 0xfe, 0x23, 0x7e, 0x6a, 0x12, 0xea, 0x3d, 0x12, 0x68, 0x6a, 0xef, 0x6b, 0x52, 0xf8, 0xec, 0x89, 0x2d, 0xde, 0x53, 0xa0, 0x2c, 0xb8, 0xc8, 0xbd, 0x4f, 0x81, 0x95, 0x90, 0x7a, 0xa4, 0x3d, 0x1, 0xa6, 0x7b, 0x4f, 0xd6, 0x6b, 0xe0, 0xb2, 0x7, 0xe5, 0x6a, 0x9, 0x98, 0xd2, 0xdb, 0xf3, 0x82, 0x6, 0x2d, 0xbe, 0x3a, 0xf3, 0xce, 0x84, 0xe6, 0x70, 0xf, 0xe8, 0x7f, 0xcf, 0x3b, 0xf7, 0xce, 0x91, 0x76, 0x59, 0x3a, 0x2c, 0x42, 0x7f, 0x79, 0x74, 0x23, 0x51, 0x60, 0xc8, 0x15, 0x32, 0x4, 0x6, 0x3f, 0xdd, 0x24, 0x3c, 0x44, 0x95, 0xe, 0x7e, 0x30, 0xdc, 0x32, 0xf8, 0x85, 0x7f, 0x58, 0x9, 0x80, 0x5, 0xdf, 0xf8, 0x87, 0x49, 0xc8, 0xe, 0x35, 0x8c, 0x33, 0xa1, 0xc4, 0x83, 0x4, 0xf1, 0xc1, 0x90, 0x3, 0x77, 0x40, 0x75, 0xe2, 0xb, 0x1d, 0xe, 0x32, 0x18, 0x5d, 0x1c, 0x99, 0x3c, 0x2e, 0x2, 0x11, 0xc3, 0xc2, 0x12, 0x22, 0xd, 0xd, 0x5e, 0x45, 0xb7, 0x35, 0x93, 0x4a, 0x43, 0x6a, 0x4d, 0x13, 0x3, 0xac, 0x43, 0x54, 0xd2, 0x35, 0x80, 0x4b, 0x81, 0x88, 0x17, 0x82, 0x8e, 0x3e, 0xaf, 0x60, 0x85, 0x11, 0xf, 0x93, 0x66, 0x6c, 0x12, 0x3, 0x78, 0x82, 0xc0, 0x5, 0xc2, 0xc6, 0x93, 0x4b, 0x68, 0xe9, 0xcb, 0xac, 0x4, 0xa, 0xc4, 0xd7, 0xbe, 0xf7, 0xe9, 0x37, 0x5f, 0x3d, 0x16, 0xa2, 0xc1, 0x97, 0x24, 0x6a, 0x79, 0x26, 0xeb, 0x84, 0xb5, 0xb6, 0xc, 0xa0, 0x87, 0xe1, 0x38, 0xb6, 0xc, 0x30, 0x6c, 0xdd, 0xb3, 0xc1, 0xb5, 0x92, 0xe, 0x44, 0x62, 0x3, 0x62, 0xb0, 0x42, 0xfc, 0xf7, 0x6c, 0x7a, 0x1a, 0xd, 0x49, 0xb9, 0x87, 0xbf, 0x24, 0x74, 0x9f, 0x6f, 0x59, 0x55, 0x10, 0xc, 0x38, 0xe6, 0x4d, 0xe5, 0xa0, 0x13, 0x1f, 0xd7, 0x26, 0x7b, 0xcb, 0xbb, 0x8a, 0x48, 0xf5, 0x2d, 0x13, 0x8c, 0x5d, 0x57, 0x29, 0x6e, 0x11, 0x41, 0xa1, 0x1b, 0xda, 0x8f, 0x28, 0xab, 0x46, 0xc7, 0x7, 0x7, 0x8d, 0x4, 0x17, 0xb7, 0xb8, 0x65, 0xd8, 0x96, 0x6b, 0xd1, 0xf9, 0x80, 0x5f, 0x2, 0x6d, 0xa9, 0xa7, 0x7e, 0x8f, 0xad, 0xdf, 0xc7, 0x3, 0xb9, 0x55, 0x6b, 0x2a, 0xf4, 0x20, 0xae, 0xb6, 0x51, 0x77, 0x3f, 0xa1, 0xd1, 0xe5, 0x45, 0xe5, 0xeb, 0xf, 0xc0, 0x1a, 0x21, 0xf0, 0xac, 0xce, 0x2e, 0xd, 0x86, 0x43, 0x4a, 0x46, 0x88, 0x9d, 0x5, 0xb0, 0xc1, 0xde, 0x87, 0xce, 0xb3, 0x9e, 0xf8, 0x8f, 0x44, 0xeb, 0x2, 0xc0, 0xfd, 0x84, 0x72, 0x3, 0xac, 0x93, 0x95, 0xae, 0x81, 0x19, 0x7b, 0x70, 0x3a, 0x3c, 0x38, 0xa8, 0xfb, 0xa2, 0x5d, 0x1f, 0xa2, 0x9e, 0x7b, 0xcb, 0x60, 0xa8, 0x16, 0xac, 0x8, 0xc5, 0x9a, 0xc0, 0xc8, 0x7f, 0x21, 0xa6, 0x5f, 0xe0, 0x2a, 0xe2, 0xb4, 0x1c, 0xfb, 0x5, 0xdd, 0x4d, 0x8d, 0x39, 0xc6, 0xc1, 0xed, 0xad, 0x44, 0xb4, 0x72, 0x53, 0x4, 0xb3, 0x46, 0x1c, 0x6f, 0xd4, 0xe6, 0x6d, 0xc5, 0xc2, 0x69, 0xd5, 0x62, 0xf8, 0x25, 0x75, 0x9, 0x1d, 0xf, 0xb2, 0x8a, 0x5f, 0x4, 0xa, 0x5a, 0xa7, 0xb8, 0x96, 0xc0, 0xd6, 0x89, 0xd2, 0x4d, 0xc6, 0x9, 0xc6, 0xc0, 0xd, 0x9, 0xe0, 0x64, 0xa8, 0x91, 0x3d, 0xae, 0xe9, 0xd6, 0xe0, 0xf, 0xb7, 0x6c, 0x11, 0x77, 0xaf, 0x95, 0x1c, 0x46, 0x1b, 0x4e, 0xff, 0x2a, 0xf4, 0x74, 0x9a, 0x8b, 0x90, 0x53, 0x85, 0x31, 0xd1, 0x24, 0x5, 0xd7, 0x19, 0x7, 0x3, 0x3c, 0xc, 0xbe, 0x0, 0xc4, 0x5f, 0x1c, 0xbd, 0xf4, 0x47, 0x74, 0x2, 0xa9, 0x2f, 0xc1, 0x9c, 0xc5, 0xe2, 0x8, 0xaa, 0x5f, 0xac, 0x17, 0xf7, 0x46, 0x1, 0x2, 0xdb, 0xba, 0xac, 0xcc, 0xf3, 0x42, 0x8a, 0xba, 0x48, 0xee, 0x9b, 0xa6, 0xd, 0xc0, 0x6e, 0xd1, 0xc8, 0x62, 0x52, 0xd0, 0x6e, 0x19, 0xf0, 0x59, 0x5d, 0xb5, 0xc, 0x58, 0xe8, 0x8f, 0xba, 0x5b, 0xc0, 0x89, 0x84, 0x6d, 0x7e, 0x37, 0xa5, 0x46, 0xc6, 0x1a, 0x8f, 0x0, 0x53, 0xa0, 0x2f, 0x87, 0x14, 0x93, 0x3b, 0x31, 0x95, 0xc4, 0xce, 0x41, 0x8c, 0xf5, 0x61, 0x2c, 0x8b, 0xb, 0x2e, 0x36, 0x36, 0x75, 0x9d, 0xa, 0x63, 0xa5, 0xc5, 0xb1, 0xd8, 0x6, 0x21, 0x2c, 0x9d, 0x31, 0x7, 0xe8, 0x4c, 0xf0, 0xf7, 0x35, 0x28, 0xcb, 0x95, 0x44, 0xdc, 0xde, 0xde, 0xc0, 0xba, 0x30, 0xb5, 0x7, 0xb3, 0x45, 0xca, 0xbf, 0x2c, 0x4a, 0x6e, 0xae, 0x98, 0x26, 0xfd, 0xa9, 0x5a, 0x6a, 0x64, 0xae, 0x47, 0xc4, 0x87, 0xb5, 0x27, 0x4c, 0x9a, 0x8, 0x9c, 0x74, 0x30, 0x6, 0xfe, 0x7b, 0xdf, 0xe7, 0x93, 0x1a, 0x8, 0xd3, 0x0, 0x70, 0x6a, 0x58, 0x9f, 0xb8, 0x14, 0x7, 0x38, 0xe, 0xd2, 0x28, 0x15, 0x1c, 0xe9, 0xfe, 0x17, 0x50, 0x84, 0xa0, 0x54, 0x23, 0xb4, 0xb1, 0x5, 0xa6, 0x22, 0xdd, 0x6, 0x55, 0xa5, 0xec, 0x9d, 0xa2, 0x96, 0x56, 0x6e, 0x49, 0xaa, 0xf, 0x38, 0xb6, 0x2e, 0x48, 0x5b, 0xea, 0xb8, 0x93, 0xf0, 0x63, 0x4b, 0xa7, 0x12, 0xd0, 0x10, 0x62, 0x3a, 0xdd, 0xe6, 0xc1, 0x99, 0xc0, 0xc1, 0x93, 0x7, 0x7, 0xe1, 0x5b, 0x5d, 0x5c, 0xa8, 0xb1, 0x7d, 0x2b, 0xf6, 0x43, 0x8e, 0xce, 0x75, 0x8e, 0xbe, 0x55, 0x48, 0x6a, 0xb5, 0xdc, 0x24, 0xaf, 0x7d, 0xaf, 0xee, 0x12, 0x95, 0xa, 0xc4, 0x2c, 0xca, 0xcb, 0x14, 0x77, 0xed, 0x1d, 0x7b, 0xf8, 0x5c, 0x61, 0x14, 0xd1, 0x8c, 0xa0, 0x86, 0x65, 0x17, 0x55, 0x71, 0xb7, 0x61, 0x10, 0x3f, 0x53, 0xf, 0xb1, 0x25, 0x42, 0x36, 0x5d, 0x2, 0x6e, 0x2a, 0xef, 0x3b, 0x2e, 0x7, 0x1b, 0xf6, 0xdc, 0xb7, 0x24, 0x8, 0xd7, 0xd5, 0x10, 0x49, 0x24, 0x5b, 0x35, 0x9, 0x8e, 0xec, 0xff, 0x7d, 0xe9, 0x22, 0x25, 0x9a, 0xda, 0x15, 0x1c, 0x35, 0x2d, 0xb3, 0x93, 0xcf, 0x71, 0x71, 0x39, 0x35, 0x2b, 0x80, 0x57, 0x60, 0x38, 0xe9, 0x45, 0xf1, 0xe6, 0xbe, 0xfd, 0xab, 0x5b, 0x35, 0x81, 0xb0, 0xf0, 0x9a, 0x6e, 0x20, 0xaf, 0xe3, 0xe0, 0x24, 0xb4, 0x13, 0x61, 0x80, 0xf5, 0x4d, 0x5c, 0xeb, 0x82, 0x8f, 0x6, 0x76, 0xc7, 0x1d, 0x9f, 0xbb, 0xd9, 0x67, 0x8a, 0xc4, 0xa6, 0x1c, 0x25, 0xc7, 0x80, 0x36, 0x4f, 0x6a, 0xb1, 0xbe, 0xcb, 0xaa, 0x45, 0x27, 0x76, 0x17, 0x1a, 0x75, 0x44, 0x52, 0x82, 0x75, 0x40, 0x14, 0xf0, 0x66, 0xdd, 0xe0, 0x12, 0xc5, 0xf9, 0x42, 0x92, 0x8e, 0x4, 0x50, 0x62, 0x1, 0x38, 0x2c, 0xd3, 0x40, 0xe0, 0x5, 0x42, 0x72, 0xc8, 0xfa, 0xc, 0x3, 0xbc, 0x6d, 0x32, 0xb6, 0xfb, 0xf6, 0xd6, 0xa4, 0xb7, 0x4a, 0x50, 0x73, 0x2d, 0xe5, 0x2c, 0xb8, 0x51, 0x84, 0x3, 0xfb, 0x27, 0x41, 0x77, 0x12, 0x9b, 0x8c, 0x42, 0x10, 0xe2, 0xd5, 0x14, 0xe0, 0xa7, 0x9c, 0x63, 0xd3, 0xfe, 0xfe, 0x30, 0x8, 0x53, 0x9a, 0xa8, 0xac, 0x60, 0x8d, 0xb9, 0x1e, 0xa8, 0x6a, 0x18, 0x3f, 0xf5, 0x7c, 0x25, 0x8e, 0xd2, 0xd8, 0x63, 0x8c, 0xca, 0x8, 0x7d, 0xa7, 0xe9, 0x7, 0x81, 0x12, 0x68, 0x82, 0x18, 0x18, 0x75, 0x22, 0x3d, 0x7e, 0x30, 0xa6, 0x89, 0xa, 0x25, 0xab, 0x3c, 0x77, 0xc6, 0x84, 0xc4, 0x38, 0xbe, 0x40, 0x58, 0xec, 0x5a, 0xbd, 0xee, 0xe9, 0x2b, 0xfd, 0x57, 0x24, 0x17, 0x81, 0x2e, 0x9c, 0xd4, 0x71, 0xf6, 0x3, 0x36, 0x8f, 0xec, 0xd5, 0x48, 0x83, 0x30, 0x1e, 0xcf, 0x14, 0xe2, 0x9f, 0xe9, 0x35, 0x9b, 0xc3, 0x2a, 0xa9, 0x11, 0xce, 0x69, 0x71, 0x36, 0xb9, 0xbd, 0x9f, 0xf6, 0xfe, 0x8b, 0xad, 0xf2, 0x83, 0x16, 0x60, 0xab, 0xcd, 0x30, 0x80, 0xc8, 0x57, 0x69, 0xc6, 0x32, 0x69, 0x56, 0x90, 0xf6, 0xe5, 0xdd, 0xf0, 0x8e, 0x40, 0x38, 0xe6, 0x7e, 0xe2, 0x78, 0x17, 0x59, 0xda, 0xd9, 0x4e, 0x52, 0x96, 0xf5, 0x51, 0x90, 0xe7, 0x28, 0x40, 0xa6, 0x7c, 0x3e, 0x5f, 0x72, 0x17, 0x77, 0xef, 0x3c, 0xb3, 0xa, 0x68, 0x69, 0x32, 0x63, 0xa1, 0xce, 0x98, 0xa8, 0x43, 0x99, 0xda, 0x9d, 0x4, 0xe1, 0x34, 0x0, 0xa8, 0x43, 0x94, 0xe0, 0x3, 0xb8, 0xd, 0x70, 0x74, 0x82, 0x99, 0x59, 0xad, 0xf9, 0xa5, 0x5b, 0x96, 0xb2, 0x50, 0x3d, 0x94, 0xca, 0x8a, 0x4d, 0x29, 0x55, 0x33, 0xcf, 0x5, 0x3e, 0x5, 0xb4, 0xaf, 0x98, 0x82, 0xf8, 0xf6, 0x16, 0x55, 0xc5, 0xc0, 0x73, 0xf2, 0xab, 0xea, 0xee, 0xf6, 0xb0, 0xd4, 0xdd, 0x6d, 0xe1, 0xb5, 0x8f, 0xab, 0xad, 0x21, 0xc9, 0xda, 0x4a, 0x22, 0x9b, 0x38, 0x56, 0xc7, 0xa2, 0xf5, 0x35, 0x62, 0x1d, 0xab, 0xad, 0x27, 0xe4, 0xec, 0xeb, 0x43, 0xf0, 0xf, 0xc9, 0x3e, 0x30, 0xd4, 0xe0, 0x22, 0xf, 0x41, 0x3d, 0x60, 0xda, 0x44, 0x1e, 0xb9, 0xba, 0x8d, 0x10, 0x65, 0x18, 0xd8, 0xac, 0x8e, 0x79, 0xde, 0x7b, 0x6c, 0x49, 0x64, 0xf4, 0x4a, 0xc5, 0xb0, 0x49, 0x29, 0x8, 0x4a, 0x6e, 0xd8, 0x48, 0x89, 0xd4, 0xb5, 0xba, 0xe7, 0x85, 0x9e, 0xd7, 0x4b, 0x9c, 0x83, 0x34, 0xca, 0xcb, 0x61, 0xa2, 0x8e, 0xbc, 0x1e, 0x66, 0x52, 0x2b, 0xa8, 0xa5, 0x42, 0x53, 0x32, 0xed, 0xda, 0x24, 0x24, 0xb9, 0xbd, 0x1d, 0xdd, 0x39, 0x3, 0x81, 0x97, 0x90, 0xe1, 0xd5, 0xe8, 0x9a, 0x6e, 0x97, 0x48, 0x17, 0x9c, 0x8, 0x45, 0xf, 0xe9, 0xb6, 0x92, 0xe0, 0x3b, 0x31, 0x47, 0x90, 0xba, 0xd0, 0x20, 0x41, 0x28, 0x73, 0x64, 0x5a, 0xc2, 0xe4, 0x2, 0x0, 0x3, 0xc5, 0x94, 0xd8, 0x59, 0x9b, 0x6, 0x24, 0x1, 0xed, 0x84, 0x81, 0x78, 0xf, 0xe, 0x54, 0x97, 0x38, 0x57, 0xad, 0xa3, 0x4, 0xee, 0x4c, 0x27, 0x36, 0x5b, 0x38, 0x38, 0x48, 0xd4, 0x22, 0x41, 0xb6, 0x5a, 0x27, 0xd4, 0x7d, 0xf2, 0x30, 0x56, 0xc2, 0xeb, 0x43, 0x6b, 0x8d, 0xe2, 0xdd, 0xa7, 0xae, 0x35, 0x6b, 0x54, 0x41, 0xd6, 0xa, 0x13, 0xa7, 0x0, 0xf3, 0x9d, 0xe6, 0x4e, 0x99, 0x96, 0x66, 0x57, 0x40, 0x18, 0xc3, 0x8e, 0xdb, 0x8a, 0x4f, 0xc9, 0xcc, 0x26, 0x66, 0x77, 0xef, 0x44, 0x22, 0x58, 0x7, 0x34, 0x7e, 0xf9, 0x87, 0x5e, 0x69, 0x26, 0x93, 0xd4, 0xf2, 0x11, 0x95, 0x53, 0x53, 0x7, 0xde, 0x80, 0xe1, 0xb5, 0x75, 0x68, 0xb, 0xc9, 0xe2, 0xb4, 0xd0, 0x85, 0x76, 0xdf, 0xeb, 0xd5, 0x57, 0x47, 0x2b, 0xe6, 0xf5, 0x3f, 0x18, 0x35, 0xd, 0x95, 0x80, 0x3c, 0xba, 0xc6, 0x46, 0x17, 0x32, 0x29, 0x34, 0x17, 0x1a, 0x3f, 0x35, 0xb9, 0x10, 0xb2, 0x7f, 0xc4, 0x27, 0x3f, 0xf8, 0x1c, 0xed, 0x20, 0xd8, 0x65, 0xfc, 0xfe, 0xa7, 0x9b, 0x52, 0x2f, 0x91, 0xa9, 0x68, 0x1d, 0x23, 0x4a, 0xb5, 0xe6, 0xae, 0xe8, 0xe6, 0xe0, 0x62, 0xb3, 0xac, 0xb2, 0xd5, 0x92, 0x4f, 0xc, 0x52, 0x4a, 0xf2, 0x9d, 0x57, 0xac, 0xc8, 0x2c, 0x2f, 0xe8, 0x96, 0x13, 0x5, 0xbb, 0x42, 0xa, 0x6c, 0x9e, 0x6e, 0x3, 0x85, 0xc9, 0xa8, 0x37, 0x4f, 0x77, 0xa6, 0x7a, 0x67, 0xc2, 0x4, 0xa0, 0x49, 0xcb, 0xf5, 0x85, 0xc6, 0x2e, 0x9c, 0xa5, 0x68, 0xa7, 0x35, 0xb5, 0x74, 0x20, 0x5a, 0xc4, 0xfb, 0x85, 0x59, 0xa4, 0x7e, 0x3d, 0x55, 0x74, 0x4f, 0x65, 0x2, 0x85, 0xbd, 0xa9, 0x0, 0xb2, 0x38, 0x6c, 0xd8, 0xaa, 0x3f, 0xc3, 0x7f, 0xd9, 0x92, 0xcf, 0x50, 0x77, 0x86, 0x7f, 0xfa, 0x33, 0xfa, 0xb3, 0x1d, 0xc3, 0xc1, 0x8f, 0xab, 0x2c, 0xa9, 0x29, 0xc5, 0xaa, 0x28, 0x33, 0xb1, 0x4, 0x78, 0xdb, 0x38, 0x50, 0x3f, 0x23, 0x6f, 0xcd, 0x97, 0x31, 0x5e, 0xfa, 0x3, 0xc7, 0x27, 0x8a, 0x22, 0x3d, 0xa6, 0xfb, 0x2d, 0xe3, 0x68, 0x6, 0xc6, 0x1e, 0x8f, 0x5, 0xa7, 0x60, 0x1c, 0xc9, 0x47, 0xc5, 0x26, 0xc7, 0x1b, 0xf6, 0xc7, 0xcb, 0xc, 0x46, 0xfb, 0xc, 0x56, 0xd0, 0x57, 0x50, 0x71, 0x43, 0x83, 0x9b, 0xd2, 0xa8, 0x7a, 0x52, 0xc9, 0xb9, 0x8a, 0xe7, 0xfc, 0xfb, 0x6f, 0x68, 0x42, 0xc, 0xe7, 0x82, 0x1a, 0xc6, 0x95, 0x99, 0xf9, 0x83, 0xcc, 0x24, 0xbb, 0x8b, 0xf0, 0xab, 0xb8, 0x5a, 0xc, 0xd6, 0xd8, 0x5, 0xb0, 0xe8, 0x94, 0x14, 0x30, 0x61, 0x89, 0x61, 0x67, 0x89, 0xb4, 0x60, 0xb, 0x44, 0xbe, 0x34, 0x25, 0x1, 0xc4, 0x89, 0xb8, 0x35, 0xa, 0xe2, 0xe4, 0x94, 0x4e, 0x8e, 0x25, 0xaa, 0x84, 0xe5, 0x56, 0xc2, 0x39, 0xce, 0x7a, 0x26, 0xe7, 0x8a, 0x3f, 0x78, 0x9b, 0xf9, 0x9d, 0x31, 0xe2, 0x8d, 0x9b, 0xca, 0x10, 0xbd, 0xf1, 0x33, 0xc1, 0xf2, 0x9e, 0x3d, 0x14, 0xe6, 0xa2, 0xbc, 0xcd, 0x24, 0xb, 0xf6, 0xf4, 0x9, 0xa9, 0xa6, 0xe9, 0x4e, 0x38, 0xba, 0xd1, 0x37, 0xfe, 0x52, 0xc1, 0x1b, 0x37, 0xf4, 0xb2, 0x73, 0x34, 0xf9, 0xaa, 0x5b, 0x9e, 0x76, 0xb4, 0x4c, 0x77, 0x4f, 0xf3, 0x2d, 0x99, 0x6, 0x2d, 0x80, 0x87, 0xb7, 0xaf, 0x24, 0xd1, 0x12, 0x34, 0x48, 0x6f, 0x6f, 0x87, 0x80, 0xe1, 0xd2, 0xc9, 0x22, 0x42, 0xc3, 0xc0, 0x1e, 0x10, 0x9b, 0xde, 0xdf, 0x69, 0x8d, 0xc2, 0x6e, 0xc1, 0x45, 0x30, 0xf1, 0x2, 0x99, 0xaa, 0x1e, 0x7d, 0xac, 0xae, 0x54, 0x44, 0x7b, 0xc6, 0x6d, 0x47, 0xc, 0x63, 0x15, 0x9d, 0xe0, 0xd7, 0x64, 0xd1, 0x83, 0x8e, 0xa6, 0xaa, 0x23, 0x10, 0x41, 0x91, 0x4e, 0xf4, 0xbc, 0xb1, 0xf7, 0xee, 0xfd, 0x4d, 0xa9, 0xbf, 0x3b, 0xc5, 0x2c, 0x51, 0x1b, 0x60, 0xe0, 0x5, 0x50, 0xcb, 0x5e, 0x4, 0x5d, 0xf5, 0x16, 0x88, 0x91, 0x85, 0x41, 0x8a, 0x4b, 0xae, 0x9b, 0x48, 0x2e, 0x42, 0xc8, 0xd2, 0xc8, 0x3d, 0x23, 0xe6, 0x8, 0x6d, 0xce, 0xb3, 0xe6, 0x26, 0x75, 0x49, 0x85, 0x63, 0x48, 0x33, 0x45, 0x37, 0x65, 0xee, 0xe6, 0x4d, 0xa5, 0x89, 0x2d, 0xd5, 0x35, 0x88, 0x11, 0x69, 0x97, 0xbf, 0xa7, 0x85, 0x65, 0x4f, 0x49, 0xb, 0x89, 0xf7, 0x55, 0x71, 0x9a, 0xee, 0x68, 0xdc, 0x8d, 0x69, 0x70, 0xe7, 0x6b, 0x1b, 0x1a, 0x49, 0x22, 0x83, 0x1b, 0xd2, 0xe, 0xa, 0xe, 0xfe, 0x7b, 0xcd, 0xc1, 0x1b, 0x58, 0x88, 0x83, 0xac, 0x21, 0xa9, 0xdd, 0xd1, 0xcb, 0xb2, 0x77, 0x34, 0x77, 0x13, 0x3c, 0xc5, 0x66, 0xa9, 0x69, 0xfb, 0x86, 0xea, 0x50, 0x53, 0x41, 0x96, 0x6a, 0xba, 0x2e, 0xfa, 0x62, 0xbc, 0xe7, 0xf3, 0x9, 0x50, 0x51, 0x60, 0x70, 0x82, 0x5e, 0x3a, 0x78, 0x55, 0x64, 0x39, 0x11, 0x55, 0x38, 0xb3, 0x62, 0xb5, 0x15, 0xc5, 0x6e, 0x4c, 0x77, 0x27, 0xa3, 0x9c, 0x74, 0x4e, 0xb6, 0x71, 0x7, 0xb8, 0xf7, 0xbd, 0x96, 0x5c, 0xc7, 0xa9, 0x9e, 0xbe, 0x41, 0x56, 0xd3, 0xe0, 0x1e, 0x53, 0x4f, 0x1, 0xa1, 0x2a, 0xe2, 0x89, 0x5b, 0xc4, 0x70, 0x2, 0x70, 0xec, 0x64, 0xe3, 0xa9, 0xbc, 0xfa, 0xc6, 0x29, 0x29, 0x8e, 0xbf, 0x39, 0x1b, 0xc3, 0xe4, 0x72, 0xea, 0xda, 0x3e, 0x69, 0x2b, 0x32, 0xd3, 0x84, 0x62, 0x5e, 0x13, 0x7f, 0x2e, 0x3b, 0x2, 0xa1, 0x70, 0x7e, 0xd7, 0x68, 0x61, 0xd9, 0x7c, 0x32, 0x5, 0x99, 0xec, 0xcf, 0xea, 0xad, 0x9a, 0xa2, 0x38, 0xa, 0xa2, 0x98, 0x82, 0x2a, 0x4c, 0x98, 0xd, 0x8c, 0x75, 0x27, 0x34, 0xa2, 0x37, 0xa4, 0x4c, 0xd6, 0xc5, 0x72, 0xf9, 0xc2, 0x64, 0x66, 0xa6, 0x5a, 0x6c, 0x55, 0xd4, 0x41, 0x32, 0xbc, 0x9e, 0x2e, 0xec, 0xd5, 0x4c, 0xd9, 0xd8, 0xba, 0xc1, 0x48, 0x34, 0x2f, 0x5b, 0x37, 0xac, 0x52, 0xc, 0xd4, 0x6f, 0x20, 0x87, 0x64, 0xd2, 0x3a, 0xe0, 0xaa, 0x66, 0x34, 0xdd, 0x86, 0x5d, 0x99, 0xbe, 0xf1, 0xeb, 0x7b, 0xba, 0xc, 0xda, 0xaa, 0xc9, 0x7c, 0x89, 0x24, 0xe9, 0xde, 0xb3, 0xc1, 0xd2, 0xf7, 0x9e, 0xe, 0x35, 0x6d, 0xce, 0xe7, 0xfb, 0x7b, 0xcf, 0x7, 0xab, 0xee, 0x9c, 0x90, 0x64, 0x7f, 0xc4, 0xef, 0x1f, 0xc4, 0x84, 0x14, 0x19, 0x37, 0x6b, 0xb9, 0x66, 0xa3, 0xf5, 0xcf, 0x4c, 0x10, 0xee, 0x6, 0x7b, 0x21, 0x35, 0x92, 0x35, 0x97, 0xc1, 0xa3, 0x42, 0x9a, 0x76, 0x28, 0x56, 0x9c, 0xf4, 0x35, 0x13, 0xe2, 0x3d, 0x86, 0x82, 0xe3, 0x18, 0x6e, 0x81, 0x72, 0xab, 0x1a, 0x6a, 0x59, 0x52, 0xe2, 0x4b, 0x22, 0xba, 0xaf, 0xfc, 0x6c, 0x59, 0x88, 0xab, 0x8e, 0x40, 0xb0, 0x20, 0x17, 0x40, 0x82, 0xb3, 0xbc, 0xf, 0x5, 0xe0, 0xc8, 0x3, 0x89, 0x20, 0x4, 0x1, 0x3c, 0xcb, 0xce, 0xd2, 0x58, 0x42, 0x16, 0x27, 0x9e, 0xa7, 0x67, 0x97, 0x9e, 0x12, 0x8f, 0x47, 0x15, 0x84, 0x91, 0x1e, 0x36, 0xdf, 0x17, 0x6, 0x9b, 0xaa, 0x16, 0xf1, 0x1e, 0x77, 0x55, 0xa3, 0x91, 0x98, 0xf5, 0x68, 0xaa, 0x62, 0x3a, 0xbc, 0x66, 0xb3, 0xe4, 0x90, 0x45, 0xa3, 0xdb, 0xad, 0xe2, 0x3, 0x9f, 0x36, 0x94, 0xaa, 0x3b, 0xf5, 0xa, 0x4a, 0x9b, 0x13, 0xb7, 0xb7, 0xe2, 0xf6, 0x56, 0x5c, 0x26, 0x8e, 0x51, 0xbb, 0x2f, 0xb7, 0x20, 0xae, 0xd7, 0xff, 0xe0, 0xa0, 0xe6, 0xeb, 0xea, 0x95, 0xaa, 0x59, 0x3b, 0x54, 0x3, 0xc5, 0x56, 0x83, 0xf5, 0x5d, 0x34, 0x31, 0x46, 0xe8, 0x31, 0x91, 0xf2, 0xa, 0x2f, 0xcd, 0xe9, 0x5b, 0x1c, 0x7b, 0x76, 0xd6, 0x34, 0x71, 0x3d, 0x77, 0x62, 0x13, 0x65, 0xb8, 0xad, 0x2d, 0xed, 0x6, 0x47, 0x4e, 0x3d, 0x29, 0x89, 0xaa, 0xa6, 0x89, 0x1d, 0x90, 0x6d, 0xec, 0x8e, 0xb8, 0x98, 0x26, 0x96, 0x3, 0xec, 0xd6, 0x38, 0x5a, 0x9c, 0x8e, 0xd6, 0xe7, 0xc0, 0x88, 0x4e, 0xe6, 0x67, 0x1e, 0x9, 0xe6, 0x5e, 0x2f, 0x3d, 0xf, 0xbf, 0xa0, 0x94, 0xa6, 0x19, 0xc9, 0x99, 0x3c, 0xa7, 0x54, 0xc4, 0x9f, 0xd9, 0x80, 0xc, 0x2b, 0x36, 0x83, 0x5e, 0x43, 0xb7, 0x90, 0x3b, 0xaf, 0x31, 0x2c, 0xad, 0xe4, 0x54, 0x51, 0x3, 0xe, 0xc4, 0x10, 0x79, 0x2e, 0x9f, 0x64, 0x54, 0x40, 0xe5, 0x6c, 0xed, 0x20, 0x6, 0xf5, 0x8d, 0xc3, 0xf4, 0xc3, 0x63, 0x31, 0xc1, 0xf8, 0x3c, 0x6a, 0x5e, 0x9f, 0xb0, 0x19, 0x9c, 0x26, 0xe9, 0x7b, 0xa0, 0x2d, 0x8e, 0x1c, 0xa4, 0x2d, 0x6, 0x6, 0xd, 0xfd, 0x1f, 0xf4, 0x5d, 0x5, 0xaa, 0x49, 0x62, 0xbc, 0xc5, 0x15, 0xdf, 0xca, 0xa8, 0x7f, 0x1a, 0x9a, 0x96, 0x56, 0xc4, 0xf1, 0x45, 0x4e, 0xed, 0x25, 0x57, 0x8c, 0xee, 0x88, 0x90, 0x94, 0x73, 0xd, 0x58, 0x6, 0xe0, 0x8, 0xdc, 0x60, 0x16, 0x66, 0xa6, 0xd5, 0x66, 0x16, 0xd, 0xb1, 0xab, 0x6c, 0x80, 0x7a, 0x1c, 0xa9, 0xc0, 0xc1, 0x5b, 0x1c, 0x4c, 0x22, 0x25, 0x23, 0x5d, 0xdd, 0x86, 0xc7, 0x94, 0x12, 0x6a, 0xa1, 0xe0, 0x55, 0x64, 0xdc, 0xfe, 0xb4, 0xec, 0x7d, 0xd8, 0xc, 0x98, 0x45, 0x27, 0x4d, 0x5, 0x8c, 0x35, 0x27, 0xc8, 0xb5, 0xb4, 0x6c, 0xda, 0xca, 0x4c, 0xb3, 0xe4, 0x7b, 0x89, 0xa9, 0x1, 0x6, 0x4e, 0x5, 0xfa, 0x1, 0xde, 0xf0, 0x91, 0x54, 0x96, 0xc2, 0x64, 0xd8, 0xab, 0x83, 0x83, 0x1f, 0x1b, 0x7e, 0x45, 0xd2, 0x16, 0x46, 0x9f, 0x22, 0x58, 0xd6, 0xe7, 0x8f, 0x9f, 0x7d, 0xf1, 0xf4, 0x85, 0xb7, 0x6f, 0x26, 0xdb, 0x10, 0x8b, 0x86, 0xaf, 0x15, 0x49, 0xff, 0x64, 0xb, 0x7e, 0xf4, 0x2a, 0xbe, 0x8c, 0x1, 0xce, 0xb2, 0x55, 0x25, 0x6a, 0x61, 0x1e, 0x96, 0x29, 0xd7, 0xc9, 0xed, 0xad, 0x14, 0x5d, 0x38, 0xc8, 0x86, 0x82, 0xc9, 0x13, 0x9, 0x2c, 0xae, 0xb5, 0x4a, 0x44, 0x52, 0xb7, 0x81, 0x38, 0x82, 0x67, 0xe9, 0x24, 0xee, 0x79, 0x2f, 0xa, 0x60, 0x84, 0xc4, 0xc, 0xbc, 0x9e, 0x3f, 0x9d, 0x78, 0x62, 0x1e, 0x90, 0xf8, 0x90, 0x2c, 0xca, 0x3, 0x3, 0x96, 0xcc, 0x9b, 0xe4, 0x69, 0x80, 0x16, 0x92, 0x2, 0x6e, 0x89, 0x46, 0x3, 0x8, 0xbc, 0x1d, 0xfc, 0x58, 0x5b, 0xf8, 0x8, 0xdb, 0xc7, 0xb7, 0x83, 0x4d, 0x9e, 0xfd, 0x12, 0x3d, 0x82, 0x8f, 0x94, 0x43, 0x27, 0x59, 0xbc, 0xcc, 0xde, 0x72, 0x12, 0x14, 0xa2, 0x1f, 0x60, 0x18, 0x6f, 0xc9, 0x1d, 0xee, 0x2d, 0x4b, 0xb6, 0xb0, 0x94, 0x72, 0x6, 0xc2, 0x45, 0x8e, 0xfe, 0x95, 0x4e, 0x14, 0x70, 0x14, 0x65, 0xde, 0x7, 0x20, 0x37, 0xaa, 0x4f, 0x51, 0xc4, 0xbe, 0x24, 0xd1, 0x3e, 0xe, 0x4b, 0xcb, 0x2a, 0xf7, 0xe7, 0xb7, 0x19, 0xc8, 0x1c, 0xbe, 0xf8, 0x88, 0xa6, 0xbd, 0x9e, 0xe1, 0x96, 0x71, 0x51, 0xbb, 0xa0, 0x10, 0xaf, 0x86, 0xf3, 0x64, 0xd3, 0x41, 0x5e, 0x6, 0x82, 0x45, 0x5, 0x9a, 0x87, 0x3f, 0x24, 0x40, 0xfb, 0xf3, 0x33, 0xe9, 0x83, 0x77, 0x76, 0xde, 0x96, 0xe3, 0x75, 0x9f, 0xfb, 0x3e, 0xda, 0x45, 0x4f, 0x7, 0xa4, 0xb8, 0xe1, 0xfb, 0x80, 0xae, 0x38, 0xfe, 0xcc, 0x4b, 0xc0, 0xa8, 0x5c, 0x63, 0xd4, 0x12, 0x76, 0x38, 0x39, 0x38, 0x40, 0xf, 0xa1, 0x59, 0x8e, 0xe6, 0x2, 0x4b, 0x60, 0x24, 0x81, 0x87, 0x25, 0x6d, 0xf, 0x5f, 0xee, 0x47, 0xa4, 0xb2, 0xd7, 0x23, 0x35, 0x34, 0xe4, 0xbe, 0xe7, 0xf5, 0x62, 0xc5, 0x29, 0x7a, 0x3, 0x4f, 0x4b, 0xba, 0x3c, 0x24, 0x13, 0xbe, 0xbc, 0xc, 0x6b, 0xf3, 0x3d, 0x32, 0x78, 0x1, 0x89, 0x41, 0xb3, 0xba, 0x86, 0x2f, 0x48, 0x61, 0xda, 0x6b, 0x99, 0x2e, 0x5f, 0x93, 0xf0, 0xa7, 0xdb, 0x3d, 0x74, 0xf9, 0xd2, 0x88, 0x16, 0x6a, 0x2, 0x9f, 0x39, 0x38, 0xdc, 0x9b, 0x0, 0xe3, 0x8c, 0x5, 0xf6, 0x1a, 0x7e, 0x60, 0x2b, 0x5b, 0xc3, 0x4, 0x3b, 0xbe, 0x84, 0xe9, 0x66, 0xb4, 0x4, 0xe4, 0x5e, 0x76, 0x7b, 0xbb, 0xbf, 0x6f, 0x38, 0xf3, 0xfc, 0x62, 0xf4, 0xfd, 0x9a, 0xb4, 0x51, 0x50, 0xf6, 0x95, 0x50, 0x4b, 0xd5, 0xa5, 0xd6, 0xc2, 0x74, 0x19, 0x30, 0xd8, 0x2, 0xed, 0x96, 0xc5, 0xa, 0x5c, 0x44, 0x78, 0xa5, 0xcf, 0x8a, 0x68, 0x7e, 0x76, 0x81, 0xce, 0x62, 0xf8, 0x7, 0x5d, 0x96, 0xc6, 0x69, 0xcd, 0x8f, 0x1e, 0x39, 0xb8, 0x51, 0xb1, 0xc9, 0x64, 0xfb, 0x8f, 0x18, 0x2d, 0xd5, 0xe6, 0x52, 0xbe, 0xc2, 0x13, 0xca, 0x3c, 0x95, 0xb, 0x5b, 0xf2, 0x79, 0x84, 0x95, 0x80, 0xcd, 0x9d, 0xe5, 0x11, 0x7, 0xc, 0xd, 0xdb, 0x12, 0x2d, 0xe0, 0x2f, 0x4d, 0xe8, 0x35, 0xdd, 0xe0, 0xb6, 0x75, 0xae, 0x48, 0x9c, 0x96, 0x31, 0x48, 0xeb, 0x2f, 0x0, 0xd9, 0x72, 0x45, 0xfe, 0xf6, 0xe1, 0x90, 0x26, 0xfb, 0x42, 0xb1, 0x7, 0xeb, 0x12, 0x37, 0xac, 0x1, 0x12, 0x24, 0x2b, 0x40, 0xd, 0x9d, 0xf6, 0x40, 0xfa, 0x22, 0x15, 0xba, 0x86, 0x65, 0x8d, 0x32, 0x1a, 0x1c, 0xfc, 0x5, 0x11, 0x7c, 0x4c, 0x76, 0x75, 0x57, 0xd7, 0x51, 0x53, 0xd, 0x14, 0x5d, 0xa1, 0x68, 0x0, 0x1d, 0x65, 0xe5, 0x17, 0x17, 0x17, 0x3c, 0xcd, 0x60, 0x48, 0x28, 0xc9, 0xc6, 0xf3, 0x18, 0x8b, 0x3d, 0x7, 0x7e, 0x62, 0xc5, 0x53, 0x20, 0x2f, 0x37, 0xb0, 0x57, 0x71, 0x15, 0x47, 0x33, 0x61, 0x3e, 0x1f, 0x2d, 0xe5, 0x20, 0xa6, 0x68, 0xcc, 0xc, 0x83, 0x28, 0x51, 0x25, 0x8c, 0x9e, 0x81, 0xf0, 0x9f, 0x32, 0x1e, 0x91, 0x39, 0x41, 0xcd, 0x74, 0x91, 0xfd, 0x19, 0xac, 0x48, 0x3c, 0x40, 0x45, 0x3e, 0xc, 0xfb, 0x53, 0x3e, 0x8b, 0x37, 0x4b, 0xe4, 0xe4, 0x0, 0x9c, 0xa1, 0x33, 0xa3, 0x6f, 0x54, 0x30, 0xa5, 0xc0, 0xb, 0xcc, 0x7, 0x19, 0x30, 0x79, 0x82, 0x44, 0xb0, 0x42, 0xc8, 0x6e, 0x73, 0xa0, 0x3f, 0x4d, 0xfb, 0x25, 0xe4, 0x7d, 0xa7, 0x78, 0xd7, 0xdc, 0x32, 0x6c, 0xfa, 0xc5, 0x87, 0xcd, 0xc0, 0x65, 0xa1, 0x35, 0x60, 0x2b, 0x7f, 0xe, 0x30, 0x62, 0x1d, 0x9b, 0x52, 0x1d, 0x70, 0xa6, 0x65, 0x1a, 0x3c, 0xc2, 0x63, 0x9f, 0xac, 0xb1, 0x83, 0xdd, 0x0, 0x3, 0x7b, 0x5a, 0x23, 0x8, 0x67, 0x36, 0x6c, 0x7, 0xaf, 0xf8, 0xde, 0xfc, 0x6c, 0x76, 0x7e, 0x36, 0x1d, 0x64, 0xe7, 0xcc, 0x13, 0xb4, 0xa1, 0x35, 0x7e, 0xf2, 0xa0, 0x75, 0xe4, 0xc1, 0x14, 0xa6, 0x38, 0x85, 0xa9, 0x9e, 0x2, 0x8a, 0xc0, 0x2, 0x53, 0xeb, 0x49, 0x5c, 0x99, 0x12, 0x9b, 0xf, 0xc8, 0x6c, 0x1f, 0xfa, 0x2a, 0xe5, 0xa, 0x3f, 0x15, 0xeb, 0xcd, 0xd1, 0x22, 0x0, 0xf3, 0x40, 0xe0, 0x9a, 0xe2, 0xa2, 0x13, 0x9d, 0x7d, 0x63, 0xaa, 0x71, 0x12, 0x75, 0x75, 0x96, 0xc2, 0x56, 0x8e, 0xa7, 0xd, 0x56, 0xc1, 0x60, 0x17, 0xcf, 0x92, 0xf3, 0xa8, 0x62, 0x80, 0xbe, 0xb8, 0x84, 0x85, 0xd4, 0x80, 0xc6, 0x2d, 0x9b, 0x62, 0xfe, 0x6, 0xc0, 0xd1, 0x4f, 0x1, 0x1e, 0xed, 0x41, 0xec, 0x23, 0xb4, 0xb4, 0x93, 0xd1, 0xe3, 0x6, 0x9b, 0x27, 0xe4, 0x8f, 0xeb, 0x91, 0x4e, 0x50, 0x88, 0xd5, 0x49, 0x4, 0x3e, 0xc0, 0xda, 0x92, 0x42, 0xc9, 0x84, 0x1f, 0xb4, 0x72, 0x68, 0x25, 0x12, 0x57, 0xe5, 0xbb, 0xd6, 0x20, 0xaa, 0x0, 0xb6, 0xc, 0x2c, 0x73, 0x6d, 0x5a, 0xa1, 0xdc, 0x14, 0xeb, 0xc, 0x18, 0xfa, 0x78, 0x49, 0x3b, 0x10, 0xc6, 0x5b, 0xd3, 0x44, 0xf6, 0x52, 0x19, 0x92, 0x3, 0xfe, 0x41, 0x2e, 0x11, 0xe6, 0x81, 0x6b, 0x89, 0x9f, 0xa4, 0x30, 0x52, 0x90, 0x7e, 0x45, 0xd6, 0x18, 0x5b, 0x61, 0xe2, 0x39, 0x8d, 0x46, 0xd0, 0xae, 0xf0, 0xb0, 0xa9, 0xcd, 0x5b, 0x85, 0xfb, 0x1b, 0xba, 0xa1, 0xd4, 0xc6, 0xbd, 0x6c, 0xe6, 0x30, 0x92, 0x6d, 0xeb, 0xf0, 0xb6, 0xa8, 0x5d, 0xdd, 0xb2, 0x5, 0xfe, 0x93, 0x45, 0x5e, 0x91, 0xcf, 0x0, 0x33, 0x95, 0x19, 0xb9, 0x94, 0x4a, 0x92, 0xfe, 0xa, 0xd, 0x1f, 0x21, 0x31, 0xf4, 0x54, 0x1e, 0x9b, 0x2e, 0x37, 0x6b, 0xf9, 0xb3, 0xd8, 0x54, 0x1e, 0xf9, 0xd4, 0x5d, 0x14, 0x9b, 0x92, 0xe3, 0x9a, 0x40, 0xe, 0x7d, 0x3, 0xe4, 0xad, 0x3d, 0x46, 0x9f, 0x4b, 0x1e, 0x5f, 0x72, 0x95, 0x8c, 0x15, 0xc6, 0xb, 0x60, 0x7c, 0xb2, 0xe4, 0x75, 0xb4, 0x18, 0x50, 0x22, 0xf4, 0x93, 0xab, 0xef, 0xcd, 0x4a, 0x7d, 0x21, 0xf0, 0x46, 0xde, 0x57, 0xf8, 0x49, 0x2b, 0x58, 0x7a, 0x8, 0x66, 0xf8, 0x15, 0xdd, 0xa0, 0xdd, 0xd9, 0x5a, 0x99, 0xea, 0x81, 0xd0, 0x1e, 0x37, 0xd1, 0x92, 0xbe, 0x3, 0x98, 0x47, 0xc7, 0x96, 0xfa, 0x1d, 0x77, 0xb8, 0x61, 0xd, 0x7f, 0x4c, 0xfa, 0x49, 0xd4, 0x26, 0x8a, 0x2a, 0xb, 0x7, 0x9c, 0x4e, 0x25, 0x68, 0x26, 0x6c, 0xe, 0xa8, 0x53, 0xe2, 0xa5, 0x66, 0x4b, 0x41, 0x10, 0x1a, 0x80, 0xab, 0xb6, 0x70, 0x21, 0x38, 0x1, 0x22, 0x22, 0x8b, 0x2d, 0xf4, 0x84, 0xee, 0x44, 0x8a, 0x18, 0xcc, 0x27, 0x80, 0x53, 0x36, 0xb9, 0xb0, 0xb4, 0x9f, 0xa, 0x4f, 0x47, 0x35, 0x1b, 0xd9, 0x25, 0xb2, 0x73, 0x6c, 0x8e, 0x6d, 0x8b, 0x64, 0x55, 0x6c, 0x5c, 0x2d, 0xd6, 0xc5, 0x1b, 0xa2, 0xa4, 0x78, 0x6d, 0x43, 0xa6, 0xae, 0xbe, 0xc7, 0xaf, 0x56, 0xa4, 0xd0, 0xdf, 0xd3, 0x9e, 0xf9, 0x68, 0xa6, 0x87, 0xc8, 0x1e, 0x1d, 0xd4, 0xba, 0xac, 0xaf, 0x85, 0xc, 0xa1, 0x52, 0x65, 0x85, 0x4d, 0xde, 0xaa, 0xd2, 0xa8, 0x30, 0x9b, 0x49, 0x6b, 0x5e, 0x2a, 0xf, 0xac, 0x6c, 0xa3, 0x7d, 0x43, 0xf1, 0x63, 0xf5, 0x0, 0xf8, 0x71, 0x4, 0xb, 0x84, 0x8b, 0x5d, 0xb5, 0x17, 0x1b, 0xed, 0xc5, 0x37, 0x8e, 0xe4, 0x11, 0xb9, 0xf1, 0xfd, 0x24, 0x7c, 0x19, 0x6f, 0x8d, 0xe3, 0xfc, 0xc1, 0xed, 0x32, 0xbe, 0xe6, 0xeb, 0xb3, 0xef, 0x7f, 0x38, 0xff, 0x20, 0x40, 0x5f, 0xbe, 0x1b, 0x9b, 0x2a, 0x0, 0xd7, 0xd9, 0x3a, 0xba, 0x1e, 0x43, 0x32, 0xe1, 0xa2, 0x55, 0x58, 0x7a, 0x7, 0xd, 0x13, 0x15, 0x1b, 0xe5, 0x1d, 0xc5, 0xb6, 0xe3, 0x58, 0x8, 0x9f, 0x4b, 0xe, 0x19, 0xfc, 0xae, 0x95, 0x57, 0x6, 0xef, 0x72, 0xe5, 0xef, 0x57, 0xd, 0xd6, 0xdf, 0xaa, 0xb7, 0xcc, 0x2e, 0x79, 0xe4, 0x36, 0x16, 0xd5, 0x4c, 0x7, 0x89, 0xdb, 0x81, 0x1e, 0x97, 0x6f, 0x5c, 0x3, 0x15, 0x6b, 0xea, 0x43, 0x5a, 0xe, 0x88, 0xe1, 0x67, 0xf7, 0x6d, 0xb0, 0x1e, 0xf3, 0x1d, 0x4d, 0x16, 0xb9, 0xd9, 0xe2, 0xdc, 0x64, 0xb5, 0x5e, 0xb3, 0x25, 0xbb, 0xb0, 0xcd, 0xf7, 0x80, 0x7b, 0x41, 0x6f, 0xb3, 0x89, 0x2f, 0x49, 0xcc, 0xb4, 0x71, 0x53, 0x70, 0x21, 0x80, 0xa, 0x9b, 0x99, 0x42, 0x33, 0x40, 0x26, 0x2e, 0x2, 0x90, 0x8a, 0x81, 0xb2, 0x3, 0xbb, 0xe2, 0x67, 0xf0, 0x6f, 0x46, 0xd8, 0x1e, 0xb0, 0x6b, 0x6, 0xdc, 0xd4, 0x22, 0x9a, 0xa3, 0x97, 0x17, 0x10, 0x13, 0xee, 0x2f, 0x20, 0x73, 0x21, 0x2c, 0xd9, 0xc9, 0x69, 0xb, 0x73, 0xd1, 0xe3, 0x5e, 0x31, 0x17, 0x59, 0xb4, 0x81, 0xd6, 0x9a, 0xda, 0x57, 0xa4, 0xec, 0x20, 0x74, 0xf9, 0xaf, 0x5d, 0x6e, 0x8, 0xa5, 0xf, 0x92, 0x34, 0xc9, 0x4a, 0x28, 0x9b, 0x65, 0x6e, 0x6, 0xb, 0x39, 0x2b, 0x68, 0x60, 0xd9, 0xe6, 0xe6, 0x0, 0x6d, 0xc7, 0xe8, 0x4c, 0x44, 0xac, 0x5c, 0x30, 0x90, 0x36, 0x7f, 0xc0, 0x66, 0x70, 0x65, 0xc7, 0x63, 0xb8, 0x16, 0xce, 0xe8, 0xee, 0x91, 0xdc, 0x61, 0x84, 0xef, 0x8f, 0x8f, 0x8e, 0x4e, 0xec, 0x26, 0xd9, 0xac, 0x51, 0xae, 0x15, 0xfc, 0x60, 0x38, 0x63, 0x8, 0x14, 0x9f, 0x65, 0x6b, 0xa0, 0x8a, 0x1c, 0x89, 0xe8, 0x6b, 0x58, 0x91, 0x40, 0xe, 0x6c, 0xc6, 0x0, 0x95, 0x74, 0x61, 0x33, 0x86, 0x6e, 0x78, 0x6, 0x37, 0xb8, 0x46, 0x77, 0x24, 0xd8, 0x2b, 0x60, 0x49, 0xd9, 0xf2, 0xf6, 0xf6, 0xb5, 0xb4, 0x0, 0xa6, 0x2d, 0x9d, 0xcd, 0x6c, 0xef, 0xbf, 0xb9, 0xc2, 0xa4, 0xef, 0xb4, 0x97, 0xb, 0x89, 0x51, 0x52, 0xe1, 0x54, 0xb4, 0xa0, 0x8d, 0x4c, 0x69, 0x23, 0x71, 0x3b, 0xe7, 0x6a, 0x23, 0xe7, 0x51, 0xa, 0x74, 0x30, 0x41, 0x45, 0x80, 0xdc, 0xaa, 0x39, 0x6e, 0xd5, 0xa2, 0x75, 0x3d, 0x52, 0x2a, 0x2d, 0xf2, 0x9c, 0xa5, 0xc6, 0x70, 0x81, 0xc, 0xce, 0xe7, 0x7c, 0xed, 0x6, 0xec, 0x69, 0x34, 0x13, 0x64, 0xd9, 0xf6, 0x81, 0xc1, 0x71, 0xc7, 0x3, 0x22, 0x44, 0xa8, 0x40, 0xbe, 0x12, 0x92, 0x9b, 0xe0, 0x58, 0xc5, 0x5, 0x75, 0xab, 0xf7, 0x29, 0x1, 0x2, 0x49, 0x23, 0x20, 0x55, 0x1b, 0x91, 0x52, 0x24, 0xf9, 0x15, 0xf6, 0xec, 0x54, 0x48, 0xde, 0xe4, 0xcb, 0x1f, 0xe8, 0xa2, 0x89, 0x86, 0x2e, 0x68, 0x8f, 0x49, 0x3d, 0x7a, 0xa6, 0x5d, 0xc4, 0xc0, 0xca, 0x22, 0x67, 0x24, 0x79, 0x3b, 0x21, 0xe7, 0xf5, 0x79, 0x9c, 0xa7, 0x4b, 0xb4, 0x50, 0x46, 0xc4, 0xd0, 0x98, 0xb3, 0xcc, 0x73, 0x10, 0x4a, 0x60, 0x59, 0x77, 0x5c, 0x35, 0xc1, 0xf9, 0xc2, 0xab, 0x0, 0x0, 0x99, 0xc6, 0x42, 0x4c, 0xf1, 0xda, 0x43, 0x2d, 0x43, 0x2a, 0x41, 0x17, 0x8e, 0x92, 0xdc, 0xe2, 0xb, 0x74, 0x6a, 0x93, 0xca, 0x83, 0x69, 0xe0, 0x76, 0x50, 0xe5, 0x91, 0x64, 0x47, 0x61, 0xaf, 0xa1, 0x89, 0x3b, 0x24, 0x8, 0xc, 0x59, 0xa0, 0x63, 0x54, 0x4, 0x8c, 0x6f, 0x99, 0xe2, 0x4c, 0xf6, 0x14, 0x4b, 0x22, 0x3e, 0xf6, 0x90, 0x4f, 0xd9, 0x43, 0x67, 0xef, 0xbd, 0x35, 0x47, 0x63, 0xe7, 0x3d, 0xa1, 0x37, 0xdb, 0xdb, 0xe4, 0x94, 0x48, 0x2c, 0xc8, 0x5e, 0x3a, 0x5d, 0x8a, 0xf, 0xcd, 0x89, 0xec, 0x49, 0x3e, 0x64, 0x4f, 0x73, 0x21, 0x7b, 0x9a, 0xa3, 0xd9, 0x53, 0x4c, 0xcc, 0x5e, 0xcd, 0xf0, 0xec, 0xd5, 0x4c, 0xce, 0x5e, 0xb2, 0x88, 0xf3, 0x39, 0x74, 0x44, 0xb8, 0x6f, 0xef, 0x35, 0xbf, 0xa6, 0x6, 0xe1, 0x2f, 0x10, 0xa4, 0xb2, 0xc4, 0xf, 0x68, 0x97, 0x37, 0x9d, 0x52, 0x9c, 0xbc, 0x7e, 0xdc, 0xd4, 0x1f, 0xee, 0x36, 0x28, 0x98, 0x92, 0x2f, 0x21, 0x53, 0x36, 0xda, 0x72, 0xbb, 0x51, 0x5f, 0x86, 0xe6, 0x9b, 0x62, 0xbf, 0x1a, 0xa4, 0x7c, 0x46, 0xb7, 0x58, 0xd2, 0xdb, 0x4f, 0x6c, 0x52, 0x20, 0xfd, 0xa8, 0x35, 0x6e, 0x97, 0xe, 0xba, 0xb4, 0xdb, 0xb, 0x12, 0x97, 0x3d, 0xc9, 0x8c, 0xa1, 0xe, 0x7d, 0x7f, 0x88, 0x9c, 0xd3, 0x34, 0x50, 0xa, 0x5e, 0x2, 0xf6, 0x69, 0xe0, 0x4d, 0x37, 0xd3, 0xe9, 0x92, 0x97, 0x1e, 0x22, 0x28, 0x28, 0xb5, 0x3f, 0x3d, 0xe3, 0xe7, 0x61, 0x2, 0xff, 0x44, 0xf8, 0x55, 0xdf, 0xfd, 0xa2, 0x3, 0xa3, 0x68, 0x1b, 0xf, 0xfd, 0xfe, 0x30, 0x60, 0x57, 0xe8, 0x1d, 0xb2, 0xf5, 0x77, 0xa9, 0x5b, 0x2e, 0x7c, 0xc9, 0x59, 0x8, 0xe9, 0x42, 0xc1, 0x62, 0xed, 0x2a, 0x5, 0x28, 0x54, 0x9f, 0x5, 0xc0, 0x59, 0x0, 0x54, 0xfb, 0xdc, 0xc1, 0xbc, 0xfb, 0xb6, 0xba, 0x83, 0x49, 0xaf, 0x65, 0xad, 0x52, 0x98, 0x2f, 0x8b, 0x69, 0xbc, 0x9c, 0x5c, 0xa0, 0xec, 0x26, 0x24, 0x3a, 0x5, 0x77, 0x86, 0x46, 0x3, 0x63, 0x5b, 0xc8, 0x92, 0x7, 0x7, 0x74, 0x7, 0x3c, 0x10, 0x21, 0x5, 0x7a, 0xbd, 0x83, 0x3, 0x3c, 0x5d, 0xc4, 0xbd, 0x79, 0xf1, 0xab, 0xf8, 0xea, 0x39, 0x9c, 0x8d, 0xca, 0xd6, 0x61, 0x58, 0xb5, 0xf7, 0xfb, 0x7d, 0x55, 0xb9, 0x5d, 0x15, 0xaf, 0x10, 0x2c, 0x6d, 0x6, 0x33, 0x34, 0x0, 0x64, 0x8f, 0x78, 0xa5, 0x55, 0xdf, 0x53, 0x69, 0x4d, 0xf9, 0x1c, 0x68, 0x82, 0xc0, 0xe9, 0x9, 0xde, 0x75, 0x6, 0x12, 0x7d, 0xd2, 0x99, 0x17, 0xed, 0x3e, 0xd2, 0xe5, 0x3c, 0x76, 0x6, 0x45, 0xa4, 0x63, 0x17, 0x1e, 0x31, 0xdf, 0x28, 0x66, 0x16, 0x68, 0xc7, 0x1a, 0x59, 0xd7, 0xbc, 0x9e, 0x34, 0x95, 0x54, 0x3, 0x2, 0x72, 0xe6, 0x95, 0x9b, 0x24, 0x1, 0xd0, 0xf7, 0xc6, 0xe8, 0x6e, 0x47, 0x9f, 0x62, 0x48, 0xa8, 0x71, 0x9e, 0x21, 0xb3, 0x4b, 0x41, 0x50, 0xe0, 0x74, 0x14, 0xcb, 0x4b, 0x61, 0xcd, 0xc8, 0xb1, 0xa7, 0x19, 0xf5, 0x45, 0xe4, 0x56, 0x8e, 0x41, 0xb6, 0xc3, 0xce, 0xb0, 0xaf, 0x18, 0x32, 0x2b, 0x20, 0x5f, 0x76, 0xb8, 0x15, 0x87, 0xf4, 0x9d, 0xea, 0xc5, 0x49, 0x7, 0x74, 0xee, 0x44, 0xef, 0x33, 0x74, 0x9a, 0x81, 0xc3, 0x22, 0xa4, 0xce, 0x35, 0x47, 0xc, 0x4f, 0x9d, 0x23, 0x45, 0xc4, 0x1c, 0xea, 0x3c, 0x85, 0x61, 0x50, 0xe7, 0xc2, 0x8d, 0xc, 0xb3, 0x40, 0x1a, 0x3, 0x44, 0x46, 0xbd, 0x8b, 0x39, 0xd7, 0xbd, 0x57, 0x8a, 0x45, 0x93, 0x46, 0x2f, 0xba, 0x67, 0xfc, 0x12, 0xa1, 0x27, 0x94, 0x1b, 0x1, 0x75, 0x4d, 0xd6, 0x6b, 0xa2, 0xfd, 0xc7, 0x32, 0x5f, 0xcc, 0xe, 0x5a, 0x5f, 0xf9, 0xe6, 0xbc, 0x36, 0x40, 0x4c, 0xea, 0x5f, 0x97, 0xa6, 0xba, 0x11, 0x75, 0x20, 0x91, 0xb6, 0xd7, 0x1a, 0x7b, 0x20, 0xcc, 0xe0, 0x4d, 0xf, 0x13, 0x19, 0xd1, 0xab, 0x89, 0x8, 0xf0, 0x11, 0xc2, 0x77, 0x36, 0xf1, 0x5e, 0x95, 0x40, 0x7f, 0xc2, 0xb9, 0x8e, 0xe6, 0xe2, 0x49, 0xd, 0x6f, 0xb8, 0x50, 0x49, 0x40, 0xa8, 0xae, 0xa0, 0x3c, 0xe0, 0x5, 0x11, 0x12, 0xa4, 0xee, 0xf6, 0x8d, 0x15, 0x79, 0x9, 0xfd, 0x77, 0x27, 0x71, 0xe8, 0xc7, 0x3d, 0xef, 0xc0, 0xeb, 0x4d, 0x8d, 0x48, 0x50, 0x67, 0x7, 0x93, 0xf3, 0x9b, 0x11, 0x3b, 0xde, 0x1e, 0x31, 0x6f, 0xe2, 0xd9, 0x6a, 0x5, 0x4, 0x77, 0xc0, 0xf4, 0xb8, 0x91, 0x9f, 0xc6, 0x55, 0x8c, 0x4a, 0x96, 0x94, 0xfe, 0xd6, 0x66, 0x7b, 0x82, 0x7b, 0xf2, 0x45, 0x86, 0x90, 0xbb, 0x49, 0x5f, 0x44, 0xe, 0x1, 0xf1, 0x85, 0xfc, 0x89, 0x34, 0x65, 0x1d, 0xa7, 0x74, 0xb, 0x14, 0x2f, 0x41, 0x8, 0xdf, 0x17, 0xe9, 0xa8, 0xf8, 0x94, 0x5a, 0xec, 0xbf, 0x3c, 0x41, 0x7d, 0xb7, 0xf8, 0xd9, 0x54, 0x75, 0x43, 0x2b, 0x9b, 0xf5, 0x32, 0x7a, 0x23, 0xfe, 0x32, 0xd9, 0x99, 0xfc, 0x1b, 0xb5, 0x20, 0xfc, 0xda, 0xd7, 0x50, 0x55, 0x7, 0x42, 0xd0, 0xb2, 0x36, 0x6c, 0x15, 0xe9, 0xe6, 0x88, 0x27, 0x61, 0x89, 0xaa, 0xce, 0xac, 0x32, 0xc8, 0xc5, 0xc8, 0x32, 0x2a, 0xff, 0x6, 0xba, 0xe, 0xa7, 0xc2, 0x76, 0x2d, 0x61, 0xf2, 0x70, 0x84, 0x29, 0x25, 0xa0, 0x40, 0x7, 0xec, 0x5a, 0x3d, 0x84, 0x87, 0xbe, 0xd, 0xd8, 0xc0, 0xfa, 0xc4, 0xca, 0x61, 0x17, 0x6, 0x0, 0x9c, 0x6b, 0x93, 0x5f, 0x1, 0x7c, 0x28, 0x69, 0x70, 0xc2, 0xc, 0xee, 0x95, 0xee, 0x3f, 0xe4, 0x22, 0x67, 0x4, 0xff, 0xc0, 0x41, 0xa6, 0x13, 0xe8, 0xad, 0xe7, 0x9d, 0x79, 0x3d, 0x7f, 0x51, 0x47, 0x7c, 0x8b, 0xa2, 0x99, 0x71, 0x23, 0x33, 0x9b, 0x24, 0x64, 0xc6, 0xe0, 0x9d, 0x7b, 0x88, 0x50, 0xf, 0xe, 0xe6, 0x13, 0x52, 0x91, 0xf9, 0xd9, 0x20, 0x8f, 0x2f, 0x80, 0xdf, 0x95, 0x96, 0x62, 0x61, 0x5d, 0xe3, 0xf6, 0x96, 0x9c, 0xbd, 0xeb, 0xe6, 0x26, 0x38, 0x8d, 0x8c, 0x91, 0x45, 0x9d, 0xa8, 0x8c, 0x3, 0xda, 0xa, 0xfd, 0x6, 0x2a, 0x5e, 0xa7, 0xe8, 0x97, 0xdb, 0x8a, 0xde, 0x33, 0x8b, 0x8e, 0x4e, 0x4, 0xa4, 0xbe, 0x9c, 0x9e, 0xfd, 0x74, 0x72, 0x7e, 0xe8, 0x4f, 0x42, 0x7f, 0xb2, 0x7f, 0xf2, 0xf2, 0x48, 0xa4, 0x9e, 0x6, 0x27, 0x94, 0x1c, 0x1c, 0xd6, 0x49, 0x18, 0xd, 0x67, 0x2e, 0xa2, 0xe1, 0x20, 0x20, 0xdf, 0x22, 0xc3, 0x9b, 0x25, 0xc4, 0x4a, 0x4, 0x2f, 0x8d, 0xdb, 0x8d, 0x23, 0x60, 0x68, 0x3b, 0x8b, 0xc1, 0x51, 0x80, 0xfc, 0x2c, 0xf2, 0x8c, 0xe4, 0x23, 0x3a, 0x44, 0xec, 0x55, 0x24, 0xee, 0x49, 0x44, 0xfc, 0x9c, 0xd7, 0x22, 0xf2, 0xcf, 0x7, 0x47, 0x6c, 0x89, 0x7, 0xdf, 0xe, 0x12, 0x13, 0x7b, 0xc1, 0x78, 0x39, 0x58, 0xac, 0xf9, 0x4c, 0xcd, 0x6c, 0x59, 0x88, 0xb6, 0x28, 0x91, 0x29, 0xac, 0xf, 0x73, 0x87, 0x4f, 0x40, 0x7, 0xe8, 0x1, 0xfb, 0xb4, 0x26, 0xd6, 0xb4, 0xeb, 0x78, 0x2d, 0xe4, 0x7b, 0xb8, 0x6d, 0xa4, 0xcf, 0xd2, 0xa, 0x4, 0x51, 0x3, 0xf5, 0xc6, 0x74, 0x21, 0xc5, 0x2e, 0xc8, 0x98, 0xe, 0xc7, 0xb8, 0x7a, 0xc, 0xc8, 0x66, 0x1a, 0x27, 0xaf, 0x61, 0x1d, 0x7c, 0xb, 0x18, 0x67, 0xc1, 0x64, 0x6, 0x3c, 0xe6, 0xc, 0x4f, 0x39, 0x95, 0xf4, 0x7a, 0x7b, 0xbd, 0x1e, 0x3a, 0xde, 0xb7, 0xc6, 0x2e, 0x11, 0x4, 0x4a, 0x45, 0x62, 0xec, 0x67, 0xf3, 0x73, 0xf6, 0xda, 0x92, 0x5c, 0x62, 0x8c, 0xb3, 0xd0, 0x60, 0x3d, 0x3d, 0xc1, 0xe3, 0x30, 0x54, 0x7b, 0xc6, 0xd3, 0x82, 0xe8, 0x1e, 0x2c, 0xcd, 0xd, 0x7d, 0x87, 0xaf, 0xb5, 0x6e, 0x84, 0xd0, 0x2f, 0x60, 0x84, 0x8b, 0xc, 0xe, 0xe6, 0x12, 0xce, 0xc, 0xb6, 0x5, 0xcd, 0x7a, 0xc4, 0xa1, 0xc9, 0x46, 0x6c, 0x5e, 0x35, 0x1, 0x4e, 0x6b, 0xfd, 0x22, 0xbb, 0x40, 0x2e, 0xcc, 0xbf, 0x50, 0x55, 0x40, 0x6e, 0xa8, 0x2f, 0xca, 0x98, 0xec, 0x5e, 0x1d, 0xff, 0x83, 0x83, 0x57, 0x93, 0xb5, 0xff, 0xa, 0x2f, 0x2b, 0x96, 0x82, 0x90, 0x97, 0x42, 0xab, 0x92, 0xc0, 0xf0, 0x64, 0x27, 0x22, 0x83, 0xe9, 0x49, 0x46, 0x19, 0x5e, 0xad, 0x59, 0xcb, 0x96, 0xc1, 0x39, 0xcf, 0xa8, 0x19, 0x5c, 0x8e, 0x57, 0x91, 0x96, 0x8c, 0x7e, 0xf1, 0xa1, 0xb6, 0x24, 0x9d, 0xfe, 0x6b, 0x5f, 0xcd, 0x98, 0x2d, 0x41, 0x80, 0xa9, 0x1b, 0x34, 0xc3, 0x87, 0x44, 0x9a, 0x7b, 0xdb, 0x82, 0xd8, 0x52, 0xae, 0xe1, 0x8, 0x22, 0x26, 0xaa, 0xb1, 0xe8, 0xcb, 0x89, 0x3f, 0xe8, 0x5, 0xd1, 0xcb, 0x9, 0x62, 0xd1, 0xf, 0x46, 0x91, 0xd7, 0xa3, 0x80, 0x22, 0x18, 0xfb, 0xc8, 0x8a, 0x26, 0xb3, 0x40, 0x8e, 0xb9, 0x12, 0xab, 0x81, 0x7e, 0x93, 0xfe, 0x45, 0x54, 0xf2, 0x4a, 0x2d, 0x8f, 0xd1, 0x25, 0xc, 0x4b, 0x16, 0xc3, 0xad, 0xd0, 0x75, 0x2, 0x1c, 0xe5, 0x56, 0xc2, 0xdd, 0x73, 0x5e, 0x55, 0xe8, 0x55, 0x14, 0xdd, 0xe0, 0xaa, 0x85, 0x84, 0x42, 0x59, 0xcd, 0x4b, 0x84, 0x1b, 0x8d, 0xa5, 0x36, 0x8c, 0x96, 0xd, 0xfe, 0x2a, 0xd2, 0x46, 0x9f, 0x44, 0xef, 0x42, 0xa1, 0xb0, 0x22, 0xae, 0x26, 0xdc, 0x1f, 0xb2, 0xab, 0xc5, 0xda, 0x61, 0x27, 0x80, 0x6a, 0x2b, 0x79, 0x1a, 0xbe, 0xff, 0xea, 0xcb, 0xcf, 0xab, 0x6a, 0xf5, 0x8c, 0xff, 0xb2, 0x1, 0x22, 0x4, 0x83, 0x81, 0x3e, 0x56, 0x55, 0x19, 0xde, 0x8, 0xe0, 0xb, 0x9b, 0x17, 0x92, 0x6c, 0xcf, 0x3a, 0x8e, 0x1d, 0xe9, 0x57, 0x7d, 0xe3, 0xa, 0x93, 0x21, 0x98, 0x87, 0x19, 0x83, 0x3, 0x1d, 0x5a, 0x87, 0x19, 0x12, 0xd8, 0x1e, 0xb5, 0x8f, 0x64, 0x4f, 0x18, 0xe8, 0xbf, 0x12, 0xb6, 0xf0, 0xa2, 0xdb, 0x15, 0xa2, 0x54, 0x6f, 0xcb, 0x40, 0x74, 0x0, 0xa2, 0x55, 0x5c, 0xc0, 0xaf, 0x70, 0x7f, 0xc4, 0xe4, 0xf2, 0x85, 0x43, 0x66, 0xd0, 0x33, 0x9c, 0x6d, 0x2, 0x18, 0x97, 0x87, 0xa8, 0xc2, 0x12, 0x6b, 0xda, 0x12, 0xf2, 0x17, 0x28, 0xe4, 0x2b, 0x89, 0xfd, 0x66, 0x8b, 0x47, 0xe4, 0x86, 0xee, 0xb4, 0xe3, 0x1, 0x70, 0xa8, 0xb0, 0xac, 0x9c, 0xee, 0xe4, 0xd4, 0xb7, 0x2f, 0x9c, 0x61, 0x84, 0x37, 0xbe, 0xb5, 0x4b, 0x81, 0xbe, 0xb0, 0x9c, 0x9d, 0xa5, 0x68, 0x14, 0x8c, 0x7f, 0x22, 0xbb, 0xc, 0xfa, 0xea, 0x8f, 0xb, 0x38, 0xf0, 0x6c, 0x36, 0x30, 0x66, 0x0, 0xb4, 0x68, 0xe1, 0xc4, 0x53, 0x0, 0x8c, 0x84, 0xa7, 0x66, 0x44, 0x17, 0xe5, 0xf, 0xf1, 0xc7, 0x6e, 0x21, 0x5a, 0xa, 0xd, 0x74, 0x52, 0x2c, 0x7b, 0xde, 0xd1, 0x91, 0xd7, 0x3, 0x4, 0x57, 0x94, 0xd5, 0x3e, 0x14, 0xb6, 0xd3, 0x17, 0x94, 0x8e, 0xfd, 0x43, 0x8b, 0xd0, 0xef, 0x4c, 0x50, 0xde, 0x6, 0x1e, 0x54, 0x81, 0xb6, 0xf0, 0xae, 0xe6, 0xa, 0x86, 0x4b, 0xc8, 0x2c, 0x83, 0x61, 0x28, 0x62, 0x8, 0xf8, 0x16, 0xce, 0xc4, 0xa0, 0x87, 0x27, 0x42, 0xf0, 0x2a, 0xd4, 0x10, 0x69, 0x6e, 0x5f, 0x91, 0xae, 0x46, 0x62, 0x32, 0x9a, 0x29, 0xee, 0xc1, 0xbe, 0x54, 0xd, 0x4c, 0x85, 0x53, 0x30, 0xa4, 0xe0, 0x1, 0x1d, 0xc2, 0x89, 0xd7, 0xd7, 0xda, 0x19, 0x10, 0x27, 0x51, 0xb, 0xbe, 0x83, 0x7a, 0x70, 0xe2, 0x2f, 0xf3, 0x7e, 0x86, 0x63, 0x87, 0x41, 0x5, 0x6, 0x39, 0x7a, 0x99, 0xc0, 0xd0, 0x64, 0x69, 0xe0, 0xa5, 0x14, 0xfa, 0x7d, 0xd5, 0xaa, 0x35, 0x13, 0xc8, 0x77, 0x22, 0xff, 0xf6, 0xbc, 0x68, 0xe2, 0x85, 0xf2, 0x87, 0x40, 0x11, 0xe8, 0xf0, 0x90, 0x48, 0xdc, 0xc, 0x99, 0xe8, 0x6a, 0x58, 0xa3, 0x7d, 0xe0, 0x40, 0xe7, 0x62, 0xfa, 0xf, 0xd9, 0x5, 0x2c, 0x80, 0x3c, 0xc, 0x67, 0xd9, 0x39, 0xcb, 0x51, 0x4d, 0xdf, 0x8c, 0xad, 0x90, 0x9f, 0xc5, 0xb6, 0x29, 0xfb, 0x79, 0x44, 0x8c, 0xfa, 0x96, 0x55, 0xa4, 0x2b, 0xc5, 0x98, 0x66, 0xbd, 0x10, 0x68, 0xd9, 0xcb, 0x23, 0x6b, 0xe1, 0x26, 0x3a, 0x54, 0x4d, 0xd8, 0xdc, 0xc, 0xb5, 0x81, 0xec, 0x1a, 0xfa, 0x87, 0xd3, 0xb, 0x8, 0xf5, 0x6d, 0x74, 0x8d, 0x71, 0xe, 0xe5, 0x11, 0xfd, 0x1c, 0xb0, 0x10, 0xa7, 0xb8, 0x58, 0x73, 0x60, 0x3, 0x34, 0xfe, 0xbe, 0x6e, 0x41, 0xd9, 0xca, 0xf7, 0xbe, 0xef, 0xcb, 0x4a, 0x3c, 0xed, 0x23, 0x87, 0xed, 0x31, 0xcf, 0x3e, 0xef, 0x1e, 0x72, 0xbb, 0xde, 0x43, 0x9a, 0xa6, 0xc7, 0x2e, 0xd0, 0x55, 0xe6, 0x8, 0x63, 0x34, 0xf9, 0x38, 0xfb, 0xb, 0x38, 0x66, 0x2f, 0x48, 0x79, 0x70, 0x81, 0x4c, 0xd6, 0x85, 0xb6, 0x44, 0x85, 0x66, 0x30, 0x78, 0x12, 0x21, 0xbc, 0xb, 0xc5, 0xfe, 0x32, 0xcd, 0xfe, 0x5e, 0xf, 0x50, 0x5a, 0x5f, 0x67, 0x29, 0xff, 0x4a, 0xb6, 0x70, 0x70, 0xd0, 0x4e, 0x3, 0xf2, 0x1, 0xfd, 0xcc, 0x94, 0x3f, 0x97, 0xe8, 0xc8, 0xfa, 0x29, 0x81, 0x68, 0xa6, 0xd8, 0x54, 0xc1, 0x54, 0xce, 0x1c, 0x4c, 0x25, 0xc, 0xf, 0xa6, 0x21, 0x7d, 0x55, 0xfa, 0x58, 0xd7, 0x63, 0x8d, 0x96, 0x6d, 0xc4, 0xd3, 0x7f, 0xf3, 0xe6, 0x4d, 0x1f, 0x8e, 0xf6, 0x45, 0x1f, 0xb6, 0x83, 0xe7, 0x49, 0x81, 0x81, 0x12, 0x70, 0x5, 0x17, 0xb4, 0xba, 0xa5, 0x88, 0x2e, 0x82, 0xc7, 0xbe, 0x4e, 0x5a, 0x61, 0x30, 0x29, 0xf5, 0xb, 0x24, 0x69, 0x2, 0xff, 0xf6, 0xce, 0x44, 0x2b, 0x5c, 0x80, 0x9c, 0x2e, 0x97, 0xd1, 0x7c, 0x8a, 0xb, 0xb5, 0x44, 0x64, 0xdb, 0xcc, 0xfd, 0x29, 0x82, 0x4d, 0x35, 0xe2, 0x3a, 0xdc, 0x38, 0xeb, 0x0, 0x5a, 0x37, 0x9, 0xee, 0x43, 0x1, 0x9b, 0x18, 0x55, 0x68, 0x7f, 0x24, 0x7b, 0x87, 0xd2, 0x9b, 0xf2, 0x34, 0x3a, 0x1e, 0xe, 0x71, 0x91, 0xc5, 0xcf, 0x93, 0x8f, 0x87, 0x70, 0xd4, 0x3e, 0x1e, 0x52, 0x27, 0x22, 0x89, 0x6c, 0xa4, 0xd5, 0xf, 0x54, 0x88, 0x65, 0x18, 0x43, 0x2e, 0x8a, 0x2a, 0x18, 0xd, 0x5e, 0x2e, 0x5f, 0xfa, 0xe6, 0x7e, 0x5f, 0xa3, 0xc2, 0xf3, 0x19, 0x2f, 0x57, 0x45, 0x5e, 0x72, 0x31, 0x2d, 0x5f, 0x5, 0x9c, 0xeb, 0x13, 0x1b, 0x84, 0x57, 0x6f, 0x34, 0x3, 0x51, 0x6, 0x8d, 0x9f, 0xc7, 0x18, 0xf2, 0x52, 0x9d, 0x6f, 0x94, 0x78, 0xfc, 0x11, 0x43, 0x23, 0x95, 0x0, 0x35, 0x55, 0x24, 0xd8, 0x60, 0xa2, 0x59, 0xb, 0x60, 0x31, 0x14, 0x62, 0x51, 0x84, 0xe8, 0xc0, 0x9f, 0x46, 0xaf, 0xd5, 0xcd, 0x9c, 0x8, 0x87, 0x19, 0x1b, 0x1, 0x2f, 0xd1, 0x1e, 0x5b, 0x4, 0xbb, 0x4, 0x59, 0x17, 0x48, 0xf6, 0x36, 0x99, 0x94, 0xc0, 0xc1, 0x7a, 0x54, 0x62, 0x2d, 0x19, 0x89, 0x6b, 0x86, 0x27, 0x38, 0x44, 0xf5, 0x9b, 0xf8, 0x14, 0x21, 0x55, 0x4a, 0xbd, 0x52, 0x38, 0x50, 0x61, 0xdd, 0xc4, 0x54, 0xd2, 0x44, 0x72, 0x21, 0xa1, 0x64, 0x1d, 0x54, 0xcd, 0x2d, 0xb0, 0x16, 0xf0, 0x69, 0x87, 0x5b, 0xb9, 0x1e, 0x50, 0x21, 0x38, 0x95, 0x92, 0x8b, 0xb1, 0x2b, 0xb1, 0x6b, 0xdc, 0x16, 0x3a, 0xb8, 0x9f, 0x65, 0x7c, 0x99, 0x5a, 0x80, 0x54, 0x27, 0x5e, 0xa3, 0x36, 0xc6, 0x48, 0x40, 0xbd, 0xc, 0xee, 0xec, 0x23, 0x60, 0x76, 0xcb, 0xeb, 0x3c, 0x41, 0x2e, 0x73, 0x86, 0x56, 0xb3, 0xf8, 0x3, 0xe8, 0xd9, 0x18, 0xa0, 0x3, 0xd8, 0xe, 0x5f, 0xc0, 0xbe, 0x40, 0xe7, 0xec, 0x11, 0xfe, 0x85, 0xa9, 0x93, 0x0, 0x30, 0x83, 0x95, 0x2a, 0xcb, 0x37, 0xc5, 0x3a, 0x15, 0x24, 0x8b, 0xba, 0xcc, 0x83, 0xb7, 0x52, 0xd7, 0x7c, 0xcd, 0x72, 0x82, 0x58, 0xed, 0x36, 0x60, 0x72, 0x2d, 0xf, 0x3b, 0xb8, 0x96, 0xe, 0x90, 0x6c, 0x2f, 0x81, 0xe2, 0x6d, 0xd4, 0xca, 0xb1, 0x99, 0xc1, 0xe1, 0xe0, 0x9, 0x1, 0x62, 0x2b, 0x4e, 0xf1, 0x44, 0xfc, 0x21, 0x2e, 0x5, 0xb2, 0x90, 0x4e, 0xa3, 0xc6, 0xb2, 0xcd, 0xa1, 0x48, 0xce, 0xda, 0xba, 0x86, 0xb3, 0xa2, 0xa6, 0xc4, 0xe8, 0x54, 0x52, 0x35, 0xed, 0xdf, 0x10, 0xba, 0x9c, 0x35, 0x6a, 0xf5, 0xc, 0xd9, 0x2c, 0x79, 0x4f, 0xbf, 0x79, 0xfe, 0xc2, 0x93, 0xa8, 0xdf, 0x17, 0x97, 0x68, 0x30, 0x10, 0xa, 0x81, 0xf3, 0xee, 0x4d, 0x2a, 0x3a, 0x29, 0xc8, 0x60, 0xa3, 0x59, 0xbc, 0x19, 0x2, 0x7e, 0xda, 0x52, 0xfa, 0x4a, 0x1b, 0x24, 0x97, 0xcf, 0xb, 0xe9, 0xec, 0x5, 0xab, 0x22, 0x1c, 0xd1, 0xd0, 0xcb, 0xd5, 0x34, 0x5d, 0x0, 0xee, 0x57, 0x8a, 0xc4, 0x18, 0x4a, 0x2f, 0x53, 0x8a, 0x9d, 0xb1, 0x76, 0x30, 0x57, 0x96, 0x79, 0x48, 0x98, 0x89, 0x38, 0xce, 0x91, 0xf7, 0x5e, 0xc0, 0x9f, 0x11, 0xf2, 0xce, 0xaa, 0x82, 0xc5, 0x1b, 0xf1, 0x1, 0x32, 0x5f, 0xfe, 0x62, 0x12, 0xfb, 0xde, 0x49, 0x9a, 0x5d, 0x9e, 0x7a, 0x81, 0x48, 0xa9, 0xcd, 0x2f, 0xc9, 0x15, 0x45, 0x3a, 0x38, 0x2d, 0x48, 0xf5, 0xc, 0xa4, 0xff, 0x95, 0x5c, 0x1a, 0x6e, 0x19, 0xd, 0xc8, 0xf9, 0x67, 0xf2, 0xe6, 0x89, 0xa6, 0xf3, 0x36, 0x12, 0x68, 0xf6, 0xdb, 0x67, 0x5f, 0xa0, 0xc2, 0xa5, 0xc8, 0xd1, 0x5c, 0x54, 0xea, 0x15, 0x5c, 0xa, 0x71, 0x74, 0x1d, 0xd0, 0x56, 0xbe, 0x20, 0xac, 0x36, 0xca, 0xb4, 0x75, 0x0, 0x49, 0x94, 0x20, 0x3, 0x23, 0x1d, 0x1b, 0x45, 0x3c, 0x67, 0x4f, 0x8c, 0x40, 0x98, 0x9b, 0xbc, 0x25, 0xc7, 0x10, 0xe0, 0x2a, 0xde, 0xe2, 0x15, 0xf0, 0x96, 0x3d, 0x24, 0x5d, 0x50, 0x82, 0x3c, 0xbc, 0x30, 0x98, 0x3a, 0x30, 0x63, 0x6a, 0x7f, 0x78, 0x3c, 0xc4, 0xa8, 0xda, 0x3d, 0xaf, 0x43, 0x23, 0x4a, 0x1b, 0xab, 0xd, 0xdd, 0x1a, 0xd1, 0xb5, 0x74, 0xf4, 0x37, 0xa, 0x59, 0xc5, 0xb8, 0x3b, 0x84, 0xa4, 0x54, 0x3c, 0x4f, 0xf4, 0x17, 0x7a, 0xb2, 0xf9, 0xd2, 0xb1, 0xe1, 0x6, 0x8f, 0x75, 0x38, 0x65, 0x24, 0xd7, 0x87, 0xf1, 0xb6, 0xd6, 0xfd, 0x99, 0x17, 0x5, 0xe4, 0x90, 0x26, 0x35, 0xd, 0xca, 0x10, 0x9c, 0xcb, 0x90, 0x69, 0xcc, 0x90, 0x61, 0xd1, 0x91, 0x5c, 0x52, 0x4e, 0xc0, 0xdb, 0x33, 0xa1, 0x34, 0x98, 0x12, 0x1d, 0x40, 0xfc, 0xc3, 0x2b, 0x22, 0xac, 0x86, 0x71, 0xa2, 0xc1, 0xd3, 0xe0, 0xc5, 0x11, 0x5e, 0x7b, 0x60, 0x94, 0x51, 0xd4, 0x28, 0x94, 0x9b, 0xe9, 0x45, 0x86, 0x15, 0x60, 0x91, 0x3d, 0x40, 0xe5, 0x5c, 0x7d, 0x4f, 0x37, 0x55, 0x5, 0xe0, 0x2f, 0x7e, 0x20, 0x81, 0x11, 0x9f, 0xbe, 0x87, 0xca, 0xa2, 0x42, 0xa6, 0x3, 0x2b, 0x98, 0xbc, 0x9e, 0x16, 0x57, 0xf8, 0x93, 0xe8, 0x3d, 0xfe, 0x26, 0x83, 0x16, 0xee, 0xc7, 0xc0, 0x7c, 0xa2, 0x22, 0x43, 0xb8, 0x50, 0xa7, 0xf2, 0xf4, 0xe8, 0x45, 0x6e, 0x19, 0xbb, 0x1a, 0x30, 0x22, 0x6f, 0x3d, 0xcd, 0xed, 0xf0, 0xbb, 0x54, 0xfb, 0xb4, 0xbe, 0x6d, 0x68, 0x44, 0xf3, 0x3f, 0x34, 0x7b, 0x26, 0x18, 0x71, 0x66, 0xb, 0x1d, 0xb, 0x85, 0x64, 0xa8, 0x41, 0x46, 0x8d, 0x92, 0x56, 0x25, 0x6a, 0x18, 0xfa, 0xdb, 0x97, 0x5, 0x41, 0x7d, 0x59, 0xa0, 0x56, 0x91, 0x19, 0x91, 0xf, 0x1d, 0x5e, 0x1, 0x4a, 0xbf, 0xae, 0x8a, 0x4b, 0x4f, 0x5e, 0xfe, 0x8b, 0x3f, 0xac, 0xb5, 0xec, 0x49, 0x40, 0x11, 0xe2, 0xda, 0x2a, 0x76, 0x19, 0x68, 0x40, 0x5c, 0x5e, 0xca, 0x11, 0xfa, 0xb6, 0x7b, 0xbe, 0x13, 0xb6, 0x3d, 0x1d, 0xd8, 0x12, 0x8, 0xd1, 0xcd, 0x16, 0xaf, 0xe3, 0xa4, 0xc8, 0x14, 0xb, 0x43, 0x4e, 0x76, 0xf3, 0x63, 0xd8, 0x71, 0x7f, 0x37, 0x95, 0xb1, 0x31, 0x65, 0x85, 0x29, 0xad, 0xe, 0x6a, 0xf7, 0x74, 0x6c, 0xcc, 0x84, 0x62, 0x63, 0x4e, 0x7, 0x3f, 0xff, 0xfc, 0x23, 0x88, 0x4, 0x6c, 0x8a, 0x41, 0x89, 0x7e, 0x74, 0xb8, 0xdf, 0x68, 0x55, 0x96, 0x56, 0x4b, 0xa2, 0x82, 0x14, 0x6a, 0x91, 0x8d, 0xd8, 0x76, 0x1b, 0x10, 0xc3, 0xd1, 0x72, 0x99, 0x53, 0xc7, 0x44, 0x7, 0xc6, 0x16, 0x2b, 0xd9, 0x2c, 0xa7, 0x8c, 0x50, 0x9b, 0xe9, 0xd6, 0x51, 0x35, 0x82, 0x78, 0x53, 0xd4, 0x9b, 0x66, 0xb0, 0x6d, 0xf2, 0x8a, 0xde, 0xde, 0x71, 0x65, 0x32, 0x27, 0xa9, 0xe2, 0x46, 0xa, 0x55, 0x18, 0x9a, 0xee, 0x15, 0x72, 0x3b, 0x53, 0x90, 0x2a, 0x90, 0x59, 0xd0, 0x82, 0xe4, 0xdc, 0x10, 0x6b, 0x16, 0x28, 0x86, 0xa1, 0x74, 0x25, 0xcc, 0x95, 0xe9, 0x1a, 0x53, 0x67, 0x9f, 0xcd, 0x5, 0xb7, 0xf0, 0x3a, 0xc2, 0x70, 0x6, 0x58, 0xec, 0x75, 0xa3, 0xc0, 0xeb, 0xf3, 0x6d, 0x23, 0x64, 0x2e, 0x4a, 0xa1, 0x73, 0x43, 0xab, 0x4a, 0x8a, 0xc9, 0xfa, 0xa6, 0x18, 0xaf, 0x87, 0x40, 0x98, 0xa2, 0x5b, 0xa2, 0x5e, 0x2f, 0xa6, 0x28, 0x7d, 0x48, 0x5e, 0xa6, 0x67, 0xb, 0xa, 0xd1, 0xf, 0x7f, 0xa2, 0xc, 0xd1, 0xa6, 0x3a, 0x6f, 0x62, 0xd4, 0xc0, 0xa1, 0x63, 0x98, 0xdd, 0x57, 0x67, 0x40, 0xdf, 0x41, 0xf6, 0x1, 0xfe, 0xe7, 0x55, 0xdd, 0x45, 0x56, 0x2f, 0x7e, 0xed, 0x72, 0xa8, 0x2e, 0x9f, 0xc9, 0x9d, 0x97, 0x1c, 0xab, 0x81, 0x35, 0x9d, 0x99, 0x5a, 0x26, 0xe0, 0x85, 0x61, 0x35, 0x38, 0x9d, 0xc5, 0x5a, 0xe2, 0x10, 0xae, 0xc4, 0x22, 0x68, 0x7d, 0xea, 0xcb, 0x5c, 0x6d, 0xb0, 0x2a, 0x72, 0x89, 0x40, 0xa1, 0x10, 0x4e, 0x30, 0xda, 0xb2, 0x43, 0x86, 0x5a, 0xf5, 0x1, 0x4e, 0xb6, 0x82, 0xb6, 0x63, 0xcc, 0xc1, 0x48, 0x18, 0x5b, 0xa0, 0x66, 0x9b, 0x22, 0xa3, 0xab, 0x98, 0x87, 0x64, 0xd6, 0xc5, 0xaf, 0x56, 0x31, 0x0, 0x4a, 0xe4, 0xd1, 0x16, 0xa3, 0xae, 0xe, 0x95, 0x27, 0x28, 0x98, 0xb2, 0x19, 0xe2, 0x1f, 0x5d, 0xd7, 0x7d, 0xa1, 0xad, 0x77, 0x17, 0x23, 0xd8, 0xb7, 0xee, 0xb4, 0x5d, 0xe, 0x66, 0xc8, 0x1b, 0x74, 0x5d, 0xd1, 0xa3, 0x3d, 0x1a, 0x93, 0xe, 0x53, 0xb5, 0xbf, 0xfe, 0x5c, 0xc7, 0x36, 0x9a, 0xaa, 0x5b, 0x32, 0xb7, 0xbb, 0xe3, 0x42, 0x7b, 0x9f, 0xd5, 0x57, 0xd3, 0x42, 0x6d, 0xf7, 0xa9, 0x35, 0x81, 0xa4, 0xd3, 0x68, 0x4d, 0xd0, 0xd5, 0xc4, 0xf4, 0x5, 0xb, 0x2, 0xd6, 0x19, 0x50, 0x42, 0xfa, 0xba, 0x72, 0xc, 0x35, 0x3a, 0x43, 0x90, 0x9f, 0x9d, 0x8f, 0xe7, 0x9a, 0x60, 0x1, 0x22, 0x98, 0x5b, 0x47, 0x46, 0x5b, 0x58, 0x26, 0x13, 0x19, 0x4a, 0x24, 0xa4, 0xe0, 0x33, 0x30, 0xd6, 0x33, 0x69, 0x6c, 0x9, 0x9b, 0x4c, 0xd1, 0x16, 0x76, 0xf8, 0x8c, 0x88, 0xfd, 0x3c, 0x9b, 0x8a, 0xbd, 0xb1, 0x6e, 0x71, 0x4d, 0xf7, 0x24, 0xe9, 0xaa, 0x7d, 0xa8, 0x4d, 0xaa, 0x55, 0xf, 0x11, 0xc5, 0x5d, 0xa2, 0x9b, 0x1d, 0x54, 0x92, 0xb, 0xff, 0x37, 0x16, 0x1b, 0x2b, 0xe5, 0x7, 0x2c, 0x31, 0x62, 0xe3, 0xa1, 0xf3, 0x9d, 0xc4, 0x0, 0xe3, 0x3f, 0x1c, 0x1d, 0x3d, 0x5e, 0xc4, 0x6b, 0xe0, 0x24, 0xff, 0x60, 0x45, 0xc4, 0xd9, 0xa0, 0x14, 0x2, 0x8b, 0x99, 0x54, 0x9e, 0xb4, 0xbc, 0xa2, 0xad, 0xc8, 0xa2, 0x6a, 0x40, 0xe5, 0x4d, 0x1e, 0xa1, 0x92, 0xbe, 0x58, 0x49, 0x9c, 0x5f, 0xc6, 0x25, 0x94, 0x10, 0x1f, 0x62, 0x99, 0x93, 0xea, 0x2a, 0xaa, 0x94, 0x86, 0x46, 0xd7, 0xc0, 0x9b, 0x5, 0x85, 0xd6, 0xcf, 0x54, 0xc0, 0xf8, 0x5e, 0x76, 0x3e, 0xb1, 0x7e, 0x85, 0xfa, 0x66, 0x59, 0xda, 0x6c, 0xfe, 0x23, 0xe3, 0x6d, 0xc, 0x8, 0xfd, 0xb7, 0x9d, 0x7d, 0x33, 0x8c, 0x41, 0x24, 0xd6, 0x8d, 0x9c, 0x77, 0x0, 0x1b, 0xe8, 0x71, 0x79, 0xdf, 0x9, 0x47, 0x26, 0x96, 0x8b, 0x2, 0xc2, 0xab, 0xc7, 0x2a, 0xf1, 0xb9, 0x70, 0xf4, 0x1, 0x94, 0x2d, 0x93, 0x64, 0x2b, 0x9c, 0xe9, 0x4, 0x59, 0x2b, 0x97, 0xe, 0xa3, 0x46, 0x57, 0x76, 0x9d, 0x46, 0x2f, 0x8d, 0xfa, 0x16, 0x3f, 0x10, 0x97, 0x68, 0x8e, 0xf7, 0xc, 0x65, 0x7e, 0xa3, 0xbd, 0x23, 0xa3, 0x3a, 0x2b, 0xd1, 0x32, 0x35, 0xcb, 0xe3, 0xe7, 0xb0, 0x9d, 0xdc, 0x74, 0x73, 0x18, 0x73, 0xb5, 0x48, 0x65, 0x74, 0x23, 0xf5, 0xa9, 0x37, 0x71, 0x9e, 0x5d, 0x8, 0xb3, 0x33, 0x20, 0x5c, 0xfa, 0xc7, 0xf3, 0x8a, 0xaf, 0xca, 0xf0, 0x13, 0x23, 0xe5, 0x49, 0x5c, 0x52, 0x3c, 0x78, 0xe, 0x58, 0xe4, 0x9b, 0x4d, 0xf5, 0xf7, 0xd, 0x5e, 0x3e, 0x53, 0x8, 0x25, 0xea, 0x7, 0x6b, 0x97, 0xf8, 0xf1, 0x8d, 0xd4, 0x89, 0xa0, 0x52, 0x93, 0x12, 0x44, 0x53, 0x24, 0x68, 0xe8, 0xdf, 0xb4, 0xba, 0x56, 0x1a, 0xb4, 0x46, 0xbb, 0x62, 0x24, 0x7e, 0x99, 0xe5, 0xfc, 0x71, 0xb1, 0x2c, 0xd6, 0xa1, 0xb7, 0x9e, 0x4f, 0x63, 0x7f, 0xc8, 0xf0, 0x7f, 0x83, 0x51, 0xe0, 0xd5, 0xf9, 0xa2, 0x21, 0xd5, 0x13, 0xc, 0xe6, 0xcb, 0x78, 0xa, 0xbc, 0x87, 0x1e, 0xd, 0xfd, 0xc, 0xbd, 0x93, 0xf, 0x23, 0xc2, 0x93, 0x1f, 0x9e, 0xca, 0xba, 0x5f, 0x0, 0x37, 0x1, 0x7c, 0x46, 0x89, 0x41, 0xf4, 0x75, 0xe1, 0x47, 0x7c, 0x9e, 0xe5, 0xf, 0xab, 0x1f, 0xf9, 0xba, 0xd0, 0xa3, 0xff, 0xac, 0xc8, 0xab, 0xcf, 0xe2, 0x8b, 0xc, 0xa3, 0xee, 0x7f, 0xf4, 0x39, 0x5f, 0x5e, 0xc2, 0xd2, 0x26, 0xf1, 0xde, 0xd7, 0x7c, 0xc3, 0x3f, 0x62, 0x7b, 0x75, 0xa, 0xfe, 0x78, 0x88, 0xa8, 0x19, 0x3e, 0xca, 0x38, 0x2f, 0xfb, 0x88, 0xa8, 0x67, 0x5e, 0xdd, 0xc8, 0x73, 0xc, 0x15, 0x39, 0x3a, 0x36, 0x12, 0x10, 0x30, 0x43, 0x2f, 0x2f, 0xd6, 0x17, 0xf8, 0x7c, 0x82, 0x4e, 0x97, 0x53, 0xfe, 0xe3, 0x27, 0x9f, 0x7c, 0x82, 0x21, 0xff, 0x49, 0xad, 0x90, 0x5d, 0xd2, 0x7a, 0xa2, 0x12, 0xc, 0xad, 0xee, 0x1f, 0xd6, 0x40, 0x40, 0x83, 0x87, 0x79, 0xbf, 0x28, 0xa, 0x8c, 0xdc, 0x40, 0x33, 0x4f, 0x36, 0x65, 0x55, 0x5c, 0xd4, 0x29, 0x23, 0x56, 0x89, 0x6f, 0x61, 0x69, 0x11, 0x9e, 0x79, 0xda, 0x12, 0x5, 0x5f, 0x6a, 0x28, 0x36, 0xc9, 0xa2, 0x24, 0x5b, 0x2, 0xf9, 0x43, 0x66, 0x68, 0xfb, 0xda, 0x73, 0x55, 0xff, 0xb3, 0x6c, 0xb9, 0x6c, 0xef, 0xc8, 0x70, 0xf0, 0x67, 0xd8, 0x12, 0x55, 0xe4, 0x57, 0xae, 0x97, 0xd1, 0x8c, 0x58, 0xb1, 0x3f, 0x59, 0x49, 0xf6, 0x9a, 0x19, 0x39, 0x6a, 0xd5, 0x66, 0xb3, 0xba, 0x91, 0x17, 0x59, 0xf5, 0xeb, 0x37, 0xb0, 0xd9, 0x56, 0x63, 0x54, 0x75, 0xba, 0x18, 0xda, 0xb4, 0x58, 0xa6, 0xed, 0x4a, 0xae, 0xd1, 0xfd, 0x20, 0x5f, 0x55, 0x8, 0x3f, 0x51, 0x29, 0xdf, 0xb7, 0x52, 0x1e, 0xc7, 0x70, 0x94, 0xa9, 0xc7, 0x3f, 0xeb, 0xa4, 0x62, 0x9d, 0xf3, 0xf5, 0x33, 0x10, 0x3f, 0x36, 0xa5, 0x51, 0x55, 0x7a, 0xc9, 0x8e, 0x86, 0xba, 0x6f, 0xa0, 0x29, 0xe8, 0xc7, 0x81, 0xc0, 0x9f, 0xcd, 0xf6, 0xfc, 0x25, 0x9e, 0x84, 0xe0, 0xe6, 0xc3, 0x53, 0x38, 0xb, 0xf4, 0xfd, 0xe1, 0x69, 0xb8, 0x77, 0xf2, 0xe1, 0x96, 0x12, 0xf6, 0xe8, 0x74, 0xec, 0xe1, 0xf1, 0xa0, 0x8, 0x20, 0x2f, 0xda, 0x6d, 0x74, 0x95, 0xf9, 0x1b, 0xbf, 0x7e, 0x14, 0x27, 0xaf, 0xe7, 0x14, 0x44, 0x42, 0x4d, 0xb1, 0xc8, 0x1f, 0x2a, 0xbc, 0x1, 0x38, 0x77, 0x8e, 0xb6, 0x4a, 0xe6, 0x95, 0xcd, 0xd6, 0x2c, 0xa0, 0x6c, 0x15, 0xac, 0x2, 0xdb, 0x2d, 0x3a, 0xab, 0x2, 0x81, 0x2e, 0x91, 0xd1, 0x42, 0xf4, 0x59, 0x2, 0xff, 0xb4, 0xe0, 0x4b, 0xc0, 0xdf, 0x98, 0x4, 0x18, 0xb3, 0x6c, 0x84, 0x2e, 0x6, 0x82, 0xa1, 0x6e, 0xb3, 0x4b, 0xb7, 0x4d, 0x7b, 0xd3, 0x1e, 0xf1, 0x63, 0x11, 0xe6, 0xc, 0xa3, 0xf2, 0x54, 0x52, 0x48, 0x1, 0x42, 0xd9, 0xab, 0x2c, 0x81, 0x25, 0x27, 0xdd, 0x53, 0x1e, 0xd, 0xc7, 0xf9, 0x89, 0xca, 0x19, 0xe7, 0x18, 0xfd, 0x58, 0xeb, 0x9, 0xce, 0xaa, 0xb3, 0xfc, 0x9c, 0xe5, 0xda, 0xf0, 0x11, 0x95, 0x39, 0x3a, 0xa8, 0x3, 0xb6, 0x51, 0x10, 0x5f, 0x63, 0xd7, 0x28, 0xce, 0x59, 0x61, 0xd5, 0x60, 0x45, 0x24, 0xa3, 0x64, 0x59, 0x64, 0x53, 0x90, 0xc5, 0x9a, 0xdb, 0xc4, 0x89, 0xd6, 0x2e, 0xa0, 0xac, 0x4, 0xc2, 0x8a, 0xae, 0xe9, 0xdf, 0xbc, 0xc9, 0x75, 0xa0, 0x87, 0x92, 0xcc, 0x4f, 0xcf, 0xca, 0xf3, 0x8, 0xa3, 0xbc, 0xb0, 0xc, 0xd8, 0x22, 0x5c, 0xad, 0x46, 0x3c, 0xf7, 0xaa, 0x66, 0xf9, 0xfd, 0x7b, 0x2d, 0xd7, 0xc8, 0x10, 0x6, 0x80, 0x36, 0xc3, 0x3f, 0x8d, 0x81, 0x64, 0xce, 0x81, 0x54, 0x6a, 0x20, 0x18, 0x42, 0xc, 0x7d, 0x3, 0xca, 0xc1, 0x5, 0x5f, 0xcf, 0x5b, 0xa2, 0x6f, 0x75, 0xbf, 0x4d, 0xab, 0x4d, 0x56, 0x2b, 0x6d, 0xe7, 0x7e, 0x43, 0xe2, 0xab, 0xa1, 0xd1, 0xaa, 0xe8, 0x76, 0x58, 0x47, 0xa4, 0x68, 0x70, 0x15, 0xb0, 0xdf, 0xcd, 0xae, 0x64, 0x41, 0xad, 0xb1, 0xd2, 0x5c, 0x7a, 0x56, 0xc7, 0x8e, 0x13, 0x91, 0xb9, 0x2b, 0x33, 0x32, 0x37, 0x42, 0xe, 0xca, 0x17, 0xc6, 0x5, 0x8e, 0x32, 0x7a, 0xec, 0x8f, 0xb6, 0x6c, 0x1d, 0xf9, 0x40, 0xa0, 0x17, 0x7c, 0xcd, 0x1b, 0x23, 0x10, 0xcd, 0xd5, 0xa2, 0xbe, 0x64, 0x35, 0x8d, 0x9d, 0x45, 0x25, 0x36, 0xfc, 0x43, 0xd7, 0xd9, 0x14, 0x4f, 0x56, 0xda, 0x26, 0xa, 0x1e, 0xef, 0x6b, 0xd8, 0xcc, 0xef, 0x5a, 0xed, 0x22, 0xf8, 0x73, 0x32, 0xb, 0xe9, 0x8f, 0xea, 0x61, 0xc3, 0xc1, 0xe9, 0x8d, 0xc6, 0x65, 0x3d, 0xf0, 0x12, 0x6, 0x2e, 0x40, 0x3b, 0xc2, 0xbd, 0xc1, 0x33, 0x90, 0xf9, 0xb9, 0x36, 0x0, 0xc8, 0xb7, 0xaa, 0x97, 0xa7, 0x32, 0xa6, 0xd9, 0xae, 0x9e, 0xf4, 0x61, 0x31, 0xfb, 0xeb, 0x43, 0x7f, 0xa7, 0xb0, 0x5a, 0x65, 0xbf, 0x7f, 0x77, 0x4f, 0x59, 0xe, 0xcd, 0x67, 0x55, 0xe9, 0x80, 0x7a, 0xe1, 0x4a, 0x1c, 0x55, 0x7, 0x7, 0x2d, 0x18, 0x47, 0xd5, 0x3d, 0x30, 0x9f, 0x1b, 0x14, 0xbf, 0x3d, 0x90, 0x3a, 0x6, 0xc6, 0x6f, 0xc7, 0xed, 0x70, 0x97, 0xe5, 0x34, 0x2b, 0xa3, 0x66, 0xb8, 0x0, 0xa3, 0xa1, 0x88, 0x6f, 0xeb, 0x1d, 0xaa, 0xbd, 0x43, 0xb3, 0xfa, 0x9b, 0x71, 0x23, 0x1d, 0xa5, 0x28, 0x18, 0xaf, 0x3a, 0x69, 0x6b, 0x6, 0x3, 0x8f, 0x7d, 0xa3, 0x4, 0xc0, 0x25, 0x64, 0xff, 0xfc, 0x73, 0xb9, 0x81, 0x49, 0xfc, 0xfc, 0xb3, 0xdd, 0x10, 0x4a, 0x70, 0x11, 0x46, 0xcd, 0x2a, 0x56, 0x91, 0x85, 0x2b, 0x37, 0x90, 0x8a, 0x11, 0xe6, 0x5b, 0xe7, 0x65, 0xa8, 0x75, 0xdf, 0xcd, 0xf9, 0x7a, 0x9, 0x32, 0xe0, 0x7d, 0xaf, 0x57, 0xf5, 0x7a, 0x20, 0xca, 0xa3, 0x69, 0x25, 0x0, 0x62, 0xbc, 0xce, 0xad, 0x45, 0x96, 0xea, 0x2, 0x9c, 0x70, 0xb1, 0xe4, 0x4e, 0x93, 0x62, 0xbb, 0x8, 0x35, 0x71, 0x70, 0x60, 0xfe, 0x42, 0xc0, 0x64, 0x2b, 0x68, 0x3d, 0xbe, 0x48, 0x23, 0x47, 0x3, 0xc0, 0x70, 0x2, 0x9b, 0x76, 0x70, 0x20, 0xfe, 0x62, 0x29, 0x90, 0x31, 0x61, 0xd3, 0x4b, 0x11, 0x79, 0xdd, 0x81, 0x8e, 0xf6, 0x21, 0x2f, 0xfe, 0xda, 0x37, 0xa2, 0xd, 0x54, 0x78, 0x19, 0x96, 0x95, 0x9f, 0xa1, 0x75, 0x27, 0xa7, 0xe, 0xe7, 0x88, 0x44, 0xcc, 0xbb, 0xf0, 0x1a, 0x99, 0x51, 0x44, 0x23, 0xc8, 0x93, 0x1b, 0x8e, 0x3f, 0x9, 0x1d, 0x5c, 0x60, 0x95, 0x2c, 0xef, 0xae, 0x92, 0xe5, 0xcd, 0x2a, 0x97, 0x78, 0x7c, 0x13, 0x33, 0x78, 0xbf, 0x4, 0x7d, 0xf2, 0xb9, 0xc9, 0x2, 0x11, 0x29, 0xe2, 0x54, 0x1f, 0xfd, 0x6c, 0xab, 0xd4, 0x5e, 0x33, 0x7a, 0xb7, 0x85, 0x9f, 0x56, 0x4d, 0xac, 0xb0, 0x57, 0x21, 0xc8, 0x83, 0x28, 0xf2, 0x29, 0x4f, 0x80, 0xfe, 0x2d, 0x9f, 0xa2, 0xb0, 0x5f, 0xba, 0x6, 0x55, 0x7d, 0x88, 0x2f, 0x4f, 0xc, 0xf, 0xe, 0x90, 0x42, 0x1, 0x7c, 0xd7, 0x37, 0xda, 0x86, 0xe7, 0xec, 0xd9, 0xe8, 0x5c, 0x9e, 0xbf, 0x10, 0xed, 0x46, 0x9e, 0xc3, 0x1c, 0x51, 0x31, 0x9, 0xec, 0x8b, 0xb3, 0xc9, 0x43, 0x9a, 0xdb, 0xe0, 0xe9, 0x17, 0x47, 0xa3, 0x3f, 0xf, 0x61, 0x82, 0x57, 0x38, 0x41, 0x8c, 0x8, 0x97, 0xcf, 0x81, 0x4f, 0x59, 0x17, 0x17, 0x4f, 0x8b, 0xcc, 0xb4, 0xea, 0x35, 0x70, 0x55, 0x36, 0xb8, 0xea, 0x57, 0x83, 0x2b, 0x38, 0x2f, 0xd9, 0xe0, 0x1a, 0xbe, 0xae, 0x81, 0x2, 0x53, 0x63, 0xe5, 0x2f, 0xeb, 0xca, 0xe7, 0x87, 0xbc, 0x57, 0x1e, 0x96, 0xe8, 0xd4, 0x7a, 0x7c, 0x28, 0xfb, 0xe8, 0xd1, 0x5f, 0x10, 0x2d, 0xf3, 0x63, 0xbf, 0xc4, 0xb8, 0x38, 0xca, 0xd8, 0xf8, 0x14, 0xc0, 0x61, 0x78, 0x5a, 0x2, 0x69, 0x28, 0x7a, 0x75, 0xf1, 0x80, 0x81, 0x28, 0x82, 0xd1, 0x1d, 0xb, 0x96, 0x66, 0xe2, 0x15, 0x99, 0x50, 0x20, 0x88, 0x78, 0x99, 0xc5, 0xe5, 0xd3, 0xec, 0x8a, 0x2f, 0xdd, 0xeb, 0x74, 0xc, 0xe8, 0x77, 0x38, 0x19, 0x86, 0x83, 0x7, 0xb0, 0x4, 0xd7, 0x38, 0x25, 0x5c, 0x20, 0x90, 0x1d, 0x36, 0xeb, 0xcb, 0x26, 0xda, 0x42, 0x32, 0x25, 0x10, 0x52, 0x3d, 0x78, 0xfa, 0x5a, 0x15, 0x6f, 0x7c, 0x35, 0xc7, 0xe3, 0xa0, 0x67, 0xa4, 0x89, 0xd9, 0x1e, 0x7, 0x38, 0x39, 0x47, 0x25, 0xe, 0x95, 0xb2, 0x46, 0x25, 0xe, 0x95, 0x32, 0x59, 0x9, 0x48, 0xef, 0x61, 0x7e, 0xe4, 0xe7, 0xbd, 0x2, 0x8d, 0xea, 0xca, 0xc3, 0x42, 0x7c, 0x2b, 0x9f, 0x67, 0xf2, 0x6f, 0xf, 0x6f, 0xae, 0x42, 0xec, 0x3c, 0x3e, 0xa4, 0xe6, 0x60, 0xc, 0x30, 0x91, 0x10, 0xbb, 0xa6, 0x14, 0x1a, 0x1, 0x32, 0x8, 0x9b, 0x4a, 0x97, 0xed, 0x2d, 0x9a, 0x65, 0x45, 0x8a, 0x2c, 0x4b, 0xb, 0x7, 0x94, 0x33, 0xd9, 0x20, 0xff, 0xf6, 0xd, 0x6, 0xe8, 0xf8, 0x66, 0xf6, 0x55, 0x3c, 0x87, 0x13, 0xb4, 0x49, 0x79, 0xe7, 0x21, 0x98, 0x2d, 0xb, 0xc0, 0xe2, 0xf4, 0xb9, 0x2c, 0xe6, 0x90, 0x7b, 0x44, 0xdf, 0x5f, 0x7e, 0x3d, 0xc2, 0x98, 0x9d, 0xec, 0xb1, 0x38, 0x10, 0xb2, 0x55, 0x92, 0xfb, 0x9e, 0xd9, 0x17, 0xc1, 0x72, 0x91, 0x59, 0x2e, 0x96, 0x19, 0xc0, 0x1, 0x16, 0xc0, 0x68, 0x3a, 0x3b, 0xf2, 0x47, 0x83, 0x7, 0x87, 0x3c, 0xc0, 0xc5, 0x28, 0x4e, 0xa3, 0x18, 0xc8, 0x34, 0xf6, 0x3, 0xa4, 0xf2, 0x2, 0xfe, 0x8c, 0x97, 0xb0, 0x97, 0x6b, 0xf4, 0x65, 0xe9, 0x45, 0x83, 0x7, 0x6c, 0x7d, 0xa, 0xff, 0x1e, 0x1c, 0xec, 0x97, 0x93, 0x75, 0x1f, 0xbe, 0x42, 0x4a, 0x35, 0xdf, 0xfd, 0x13, 0x20, 0x36, 0x2d, 0xfd, 0x65, 0x7f, 0x8d, 0xf, 0xbe, 0x91, 0xe9, 0x62, 0x2a, 0x92, 0x13, 0x9e, 0x2d, 0xfd, 0x25, 0xf4, 0x77, 0xa8, 0xf7, 0x5, 0xb8, 0xe3, 0x4d, 0x10, 0x4, 0x8d, 0x4, 0x44, 0x5f, 0x0, 0x3e, 0xc6, 0x28, 0xd7, 0xf7, 0xa9, 0x35, 0x8b, 0xd2, 0xfe, 0xa, 0x70, 0x44, 0x23, 0xf9, 0x79, 0x64, 0xc4, 0x54, 0x9b, 0x1d, 0x5d, 0x6, 0x63, 0xff, 0xf9, 0x69, 0x7c, 0x7b, 0x1b, 0x9f, 0x1e, 0x1f, 0x3e, 0xc7, 0x8b, 0x87, 0x5, 0xbd, 0xad, 0x2, 0x69, 0xc1, 0xe5, 0x21, 0x2c, 0x4f, 0xab, 0x3c, 0x7b, 0xae, 0x4e, 0xbe, 0xbf, 0x88, 0xcc, 0x28, 0xe, 0x80, 0x79, 0x37, 0x40, 0x55, 0x9, 0xeb, 0x5c, 0x1e, 0x1d, 0x8b, 0x52, 0xc1, 0x74, 0xcd, 0xe3, 0xd7, 0xe3, 0xcb, 0x23, 0x57, 0x53, 0x2, 0x1f, 0xb9, 0xf3, 0xb4, 0x37, 0x21, 0xf4, 0xf3, 0x3c, 0x2a, 0x60, 0x22, 0xb3, 0xa3, 0xe7, 0x70, 0x8, 0x4b, 0x12, 0xd7, 0x9f, 0x33, 0xfc, 0x2b, 0x24, 0xf2, 0x4b, 0x6, 0xb8, 0x31, 0x5c, 0xe1, 0x33, 0x72, 0xe1, 0xaa, 0xf7, 0xfc, 0xf0, 0x92, 0x80, 0xab, 0x92, 0xb2, 0x41, 0x3, 0x5b, 0x68, 0x55, 0x29, 0x37, 0xb1, 0xc7, 0xd1, 0xcb, 0xef, 0xa4, 0xb1, 0x8, 0xe0, 0x32, 0x24, 0x93, 0xfa, 0x9e, 0xb, 0x8d, 0x39, 0x41, 0xd6, 0xc4, 0x62, 0x2b, 0xbc, 0x57, 0x5a, 0xad, 0x2d, 0xc, 0x14, 0xdc, 0xac, 0x88, 0xff, 0x91, 0xa8, 0x79, 0x65, 0xde, 0x55, 0x6e, 0xc7, 0x6f, 0xd0, 0xc2, 0x1a, 0x1a, 0x50, 0xa5, 0xfc, 0x8f, 0x80, 0xe2, 0x19, 0x96, 0xc3, 0x2f, 0xd7, 0x2f, 0xab, 0x97, 0xf9, 0x39, 0x5e, 0x7a, 0xed, 0x69, 0x67, 0x69, 0x90, 0x65, 0x3c, 0x15, 0x4f, 0xe0, 0xff, 0x58, 0xef, 0xd2, 0xfa, 0x3f, 0xdd, 0x7e, 0x78, 0x1a, 0x9c, 0xfd, 0xf4, 0xb2, 0x3a, 0x3f, 0xc, 0x3e, 0x12, 0xcf, 0xd2, 0xbe, 0x5c, 0x9b, 0x45, 0x5e, 0x56, 0x91, 0x3f, 0x38, 0x9c, 0x4, 0x1f, 0x9e, 0x62, 0xee, 0x47, 0xec, 0x83, 0x11, 0xfb, 0xa8, 0x6e, 0xf8, 0xff, 0xe8, 0x76, 0x3f, 0xa, 0xc6, 0x75, 0xf2, 0x87, 0xa7, 0x3a, 0x5d, 0xf, 0x53, 0x67, 0x52, 0xfb, 0x22, 0xf3, 0xe5, 0xcb, 0x8f, 0xd0, 0x1c, 0x16, 0xea, 0x2a, 0x4d, 0xf7, 0x4a, 0xe4, 0x7c, 0x44, 0xcd, 0x85, 0xe5, 0x59, 0x75, 0x1e, 0xe1, 0x3f, 0xfa, 0xb1, 0xd9, 0x9, 0x2a, 0xb1, 0x42, 0x8e, 0x3e, 0xa0, 0x95, 0xf9, 0xf6, 0x96, 0x5a, 0x5d, 0xcd, 0xce, 0x22, 0x1b, 0x2b, 0x78, 0xb3, 0x5a, 0x90, 0x10, 0x1b, 0x4, 0xa7, 0xfa, 0x8d, 0xa0, 0x2, 0x80, 0x87, 0x60, 0x3b, 0x85, 0xfe, 0xa4, 0x3, 0x6b, 0x16, 0xc4, 0xe2, 0x88, 0x9b, 0xa8, 0x4c, 0x43, 0x10, 0x49, 0x93, 0x4a, 0x54, 0x14, 0x44, 0xa, 0xfd, 0xd, 0xa, 0x43, 0x5a, 0x40, 0x7c, 0x50, 0x80, 0x90, 0x14, 0x3d, 0x86, 0x6, 0x6f, 0xc4, 0xfd, 0x1f, 0x52, 0xc, 0x40, 0x85, 0x23, 0x21, 0x19, 0x14, 0x8, 0x53, 0x9c, 0x74, 0x4c, 0x4f, 0x66, 0x33, 0x9e, 0xa0, 0x8a, 0xa, 0x91, 0x78, 0x6c, 0x70, 0x73, 0x6, 0xd2, 0xc7, 0xc7, 0x2e, 0x4a, 0xfe, 0x45, 0xfe, 0xf7, 0x4d, 0x9c, 0x3a, 0xb, 0x1c, 0xca, 0x22, 0x42, 0x55, 0xe5, 0x2a, 0xd3, 0x1f, 0x1d, 0x2, 0x41, 0xac, 0xfa, 0xc7, 0x81, 0x6a, 0xac, 0xbb, 0xac, 0x5f, 0x1d, 0x21, 0xe6, 0x39, 0x19, 0x4d, 0x0, 0x79, 0x41, 0xdb, 0x61, 0x7f, 0x8, 0x1f, 0x7e, 0xbf, 0x2f, 0x5b, 0xe8, 0x8f, 0x74, 0x23, 0x8f, 0x37, 0xd3, 0x2c, 0xe9, 0x18, 0x92, 0x31, 0xa8, 0xce, 0x62, 0xa3, 0x43, 0xdf, 0xaf, 0xa2, 0xea, 0x68, 0x4, 0x6d, 0x62, 0x8d, 0xde, 0xc8, 0x1c, 0x5f, 0x57, 0xb5, 0xe6, 0x0, 0x61, 0x88, 0x38, 0x40, 0x18, 0x5c, 0x74, 0x2c, 0x9a, 0xa9, 0xa7, 0x49, 0xaa, 0xbb, 0xce, 0x11, 0xda, 0xb, 0xe7, 0x2c, 0xd8, 0x6f, 0x8e, 0xf1, 0xb0, 0xea, 0x8f, 0x1a, 0xab, 0xe8, 0xac, 0xd8, 0x1e, 0xa5, 0x5e, 0xca, 0x7a, 0xa4, 0x87, 0xe6, 0x96, 0xfc, 0x7d, 0x93, 0xe5, 0x55, 0xc7, 0x32, 0x41, 0x63, 0xaa, 0x7b, 0x6b, 0xd0, 0xdd, 0x35, 0x1a, 0x83, 0x6e, 0x2e, 0x6e, 0x57, 0x55, 0xd7, 0xb0, 0x5b, 0xb, 0xdc, 0x58, 0xe4, 0xe7, 0x99, 0x19, 0x25, 0xdb, 0x5c, 0x3a, 0x41, 0x9c, 0x8a, 0x12, 0x5a, 0x1d, 0xd5, 0xc, 0x19, 0xb0, 0xa, 0xbd, 0x91, 0x9e, 0x44, 0x47, 0xed, 0x3d, 0x59, 0x1b, 0x4e, 0x49, 0xab, 0xb6, 0x31, 0x8f, 0xae, 0xbe, 0x69, 0xa1, 0x75, 0xf7, 0xb2, 0xee, 0x21, 0x34, 0x64, 0xc2, 0xef, 0x93, 0xab, 0x55, 0xe1, 0xea, 0x1a, 0x2f, 0x7c, 0xaa, 0xc9, 0x28, 0x34, 0x8, 0xe3, 0x31, 0x1b, 0xd, 0x71, 0x1b, 0x70, 0x45, 0x3, 0x3d, 0xf6, 0xae, 0x6, 0x46, 0xba, 0x1, 0xbf, 0x6f, 0x34, 0xd1, 0x87, 0x36, 0x70, 0x8, 0xf6, 0x56, 0xec, 0x1e, 0xc5, 0x30, 0x54, 0x8d, 0x59, 0x5b, 0xd3, 0x1c, 0x18, 0xe, 0x8b, 0x76, 0xa9, 0xd9, 0x1f, 0x9c, 0xdb, 0xc0, 0xd8, 0xab, 0xc7, 0xd9, 0xda, 0x7d, 0x62, 0x4f, 0xa3, 0xd1, 0x4, 0x0, 0x54, 0x2d, 0x34, 0x31, 0x7e, 0xa3, 0xbe, 0x2, 0xbc, 0x7a, 0xd5, 0xf0, 0x60, 0x76, 0xb4, 0xa1, 0x76, 0x4c, 0x55, 0xd5, 0x0, 0x68, 0x9d, 0x6a, 0x77, 0xe5, 0x7a, 0x72, 0xc6, 0xd6, 0xc9, 0x96, 0x2a, 0xd1, 0x7f, 0xd8, 0x4c, 0x57, 0x0, 0x69, 0xae, 0xe7, 0x13, 0x7c, 0x1a, 0xa5, 0x81, 0x36, 0x84, 0x80, 0x3d, 0x1a, 0xfc, 0xd7, 0x70, 0xf4, 0xe0, 0xcf, 0xc, 0x5d, 0x5, 0xca, 0x48, 0x7, 0xbe, 0x32, 0x56, 0x59, 0x4c, 0x16, 0x57, 0x5a, 0xc8, 0xfb, 0x83, 0x8f, 0x3, 0x56, 0x9e, 0x68, 0xbe, 0xb, 0xb2, 0x7c, 0xa8, 0xc8, 0xb2, 0x88, 0x1f, 0xfd, 0x29, 0x8, 0xf1, 0x8f, 0x5f, 0xb3, 0xf4, 0xe2, 0x3, 0x91, 0xba, 0x3f, 0x3a, 0x2, 0xe9, 0xa0, 0xef, 0x97, 0xed, 0x4d, 0x82, 0xe6, 0x83, 0x1a, 0xac, 0x8f, 0xf, 0x81, 0xf5, 0xaa, 0xfa, 0x59, 0xa0, 0x1a, 0x39, 0xe2, 0x81, 0x9, 0x5c, 0xff, 0x29, 0x53, 0xb1, 0x26, 0x42, 0x30, 0x7c, 0xc7, 0x24, 0x1a, 0xf0, 0xfd, 0xbe, 0xf3, 0x38, 0x16, 0xf3, 0x0, 0xb0, 0x30, 0x27, 0x72, 0x8, 0x4c, 0xf5, 0xaf, 0x98, 0xcc, 0xe8, 0xb4, 0x9a, 0xf4, 0x1, 0x92, 0xde, 0x6b, 0x77, 0xc2, 0xd6, 0x52, 0xdc, 0xab, 0xda, 0xe1, 0xe0, 0x81, 0xb1, 0x24, 0xa8, 0x42, 0xee, 0x5e, 0x8c, 0x71, 0x1b, 0xe9, 0xfb, 0x7e, 0xd6, 0xc3, 0x8f, 0x7e, 0x56, 0x3, 0xc7, 0xbd, 0x1b, 0x31, 0xe9, 0x80, 0x6a, 0xa8, 0x97, 0x35, 0xb6, 0xe8, 0x5e, 0xad, 0xb5, 0x48, 0x83, 0xf, 0xed, 0x1d, 0x42, 0xa1, 0x7, 0xc7, 0xf, 0x2, 0x35, 0x40, 0x9b, 0x52, 0xb4, 0x4a, 0x60, 0xcf, 0x35, 0x32, 0xc2, 0x50, 0xd0, 0x89, 0x1b, 0xf9, 0xf7, 0xdf, 0xc, 0xd4, 0x4c, 0xa9, 0x10, 0xa2, 0x1, 0x63, 0xf6, 0x5d, 0x15, 0xc5, 0x9a, 0x9d, 0x8c, 0x8e, 0x8e, 0x7, 0xff, 0xf5, 0x60, 0xf2, 0x5f, 0x83, 0x7, 0x9f, 0x1c, 0xb, 0x26, 0xe6, 0x98, 0x52, 0x60, 0xef, 0x61, 0x49, 0x64, 0x32, 0x6d, 0xdd, 0xe0, 0x1, 0x65, 0xe0, 0xd0, 0xf0, 0x4f, 0x78, 0x2c, 0x13, 0x5a, 0x25, 0x8f, 0x7, 0xc7, 0x46, 0xd1, 0xff, 0xfe, 0x18, 0xb, 0x37, 0x4b, 0x7c, 0x62, 0x15, 0xf9, 0xf3, 0x9f, 0xb0, 0x90, 0xb9, 0xca, 0x5d, 0xa3, 0x1e, 0x60, 0x77, 0xb0, 0x70, 0x62, 0xce, 0x6a, 0x5d, 0x0, 0x94, 0x2a, 0x5a, 0xcf, 0xe6, 0x52, 0x1c, 0x13, 0xf, 0xd2, 0x1b, 0x3c, 0x40, 0xf7, 0xe4, 0x29, 0xea, 0x41, 0x84, 0x1, 0x33, 0x5e, 0x33, 0x7c, 0x86, 0x8f, 0x4e, 0x3b, 0xc, 0x32, 0xa5, 0x72, 0xcb, 0x28, 0x49, 0x17, 0x12, 0x54, 0x5c, 0xc7, 0xa4, 0x13, 0xef, 0x3f, 0x3f, 0xdb, 0x59, 0xe6, 0xa2, 0x78, 0xbb, 0xbb, 0x40, 0x71, 0x47, 0xfd, 0xb2, 0x23, 0xdf, 0x1, 0x5, 0xb2, 0x8a, 0x61, 0xde, 0x5a, 0xb1, 0x11, 0xff, 0xf8, 0xe8, 0x93, 0x61, 0x40, 0x9a, 0xbe, 0xa7, 0x11, 0xdd, 0xb2, 0x27, 0x7c, 0x79, 0x8f, 0xa9, 0xd7, 0x5, 0x3b, 0x67, 0xfe, 0x78, 0x57, 0x11, 0x98, 0xf8, 0xce, 0xfc, 0x62, 0x77, 0xed, 0xd2, 0x9d, 0xdd, 0x3d, 0x6b, 0xcb, 0x74, 0xdc, 0x9e, 0xf7, 0x97, 0x28, 0xc5, 0xe8, 0xdb, 0xea, 0x2f, 0x2d, 0x2d, 0xaa, 0xd6, 0x4a, 0xb0, 0x42, 0x99, 0x4b, 0xc, 0xf1, 0x55, 0x58, 0xb2, 0x10, 0x7a, 0x33, 0x10, 0x72, 0x6, 0x5b, 0x9a, 0xeb, 0x14, 0xf7, 0x7a, 0xf2, 0xd6, 0x3e, 0x3e, 0xca, 0xd8, 0x3a, 0x42, 0x43, 0x46, 0xba, 0xe9, 0x5f, 0x2e, 0x41, 0xb2, 0x59, 0x63, 0x80, 0xcb, 0x80, 0x95, 0xc6, 0xef, 0x80, 0x65, 0xa7, 0xf1, 0xa4, 0xa8, 0x87, 0x20, 0x96, 0x7e, 0xea, 0x2f, 0x83, 0x50, 0x69, 0x16, 0x8b, 0x60, 0x3b, 0xc6, 0x4, 0xa9, 0x3, 0x7c, 0x26, 0x3, 0xc7, 0x3f, 0x55, 0xa1, 0xe4, 0x5b, 0xd8, 0x6, 0x47, 0x1d, 0x55, 0x3, 0x2b, 0xf0, 0xd3, 0xed, 0x6d, 0x85, 0xf6, 0x2, 0x3, 0x2b, 0x2c, 0x7, 0x24, 0xa2, 0xd7, 0x97, 0xa, 0x14, 0x9, 0x82, 0xda, 0x1d, 0x61, 0xe5, 0xf7, 0x40, 0x82, 0xc7, 0xbb, 0x5e, 0x5e, 0x4e, 0xfc, 0x2c, 0xd2, 0x3f, 0xd0, 0xd8, 0x32, 0xa1, 0xd2, 0xdf, 0xf7, 0xb, 0xa, 0xd1, 0xa, 0x84, 0xc8, 0x91, 0xfb, 0x3, 0xe4, 0x56, 0xc5, 0x2a, 0x8, 0xa9, 0xb2, 0xa3, 0x86, 0x5d, 0x8c, 0xa1, 0xd2, 0x8a, 0x5d, 0xa3, 0x7, 0x2a, 0x2a, 0xf4, 0x64, 0x1c, 0xb4, 0x96, 0x5e, 0xb5, 0x6a, 0x85, 0x48, 0x9b, 0xb4, 0x93, 0x7c, 0x2c, 0x1a, 0x56, 0x68, 0x6d, 0x15, 0xcb, 0x98, 0x15, 0x13, 0xeb, 0x97, 0xef, 0x15, 0xb9, 0xd7, 0x13, 0xa5, 0xce, 0xc4, 0xf7, 0x79, 0x84, 0xea, 0xf5, 0xd7, 0x84, 0x16, 0x74, 0xc, 0x33, 0x47, 0xf7, 0x8e, 0x8, 0x67, 0x13, 0x67, 0x2a, 0xe, 0x2, 0xdf, 0x9c, 0xc, 0x2b, 0x19, 0xd, 0x56, 0x8d, 0xc3, 0xf8, 0xe5, 0x1c, 0x47, 0xb2, 0x65, 0x9f, 0x21, 0xa4, 0xa2, 0xc5, 0xa4, 0xb8, 0x8e, 0x77, 0xc, 0x83, 0xac, 0x1d, 0x4b, 0xa0, 0xed, 0xea, 0x33, 0xc2, 0x1b, 0x2e, 0xeb, 0xc2, 0x2d, 0xab, 0xcb, 0x9d, 0x65, 0x96, 0x39, 0x90, 0xa, 0x7a, 0x56, 0x59, 0xf7, 0x1c, 0x5f, 0xa2, 0xe5, 0xa, 0x5e, 0xa, 0x28, 0xfb, 0x95, 0x8c, 0x19, 0xf5, 0xc5, 0x1b, 0x60, 0x32, 0x40, 0x93, 0x63, 0x58, 0x8d, 0xdb, 0x3e, 0x1a, 0xe6, 0xeb, 0x66, 0x8b, 0x5c, 0xb8, 0xde, 0x6, 0xec, 0x59, 0x44, 0xe0, 0xfd, 0x55, 0x7c, 0x95, 0x5d, 0x6c, 0x2e, 0xc8, 0x44, 0xc3, 0x75, 0xb9, 0xe3, 0x78, 0xfe, 0x2d, 0x93, 0x70, 0x43, 0x75, 0xb6, 0xec, 0x85, 0xd5, 0x90, 0x30, 0xb8, 0x79, 0xc7, 0x96, 0x44, 0x25, 0x7c, 0xf2, 0xde, 0x37, 0xdb, 0xc2, 0x3b, 0xf5, 0xf6, 0x28, 0x6d, 0xd3, 0x19, 0x67, 0x4f, 0x49, 0x75, 0x85, 0x37, 0x52, 0xb6, 0xf9, 0x4e, 0xd9, 0x32, 0xd9, 0x51, 0x1e, 0xc7, 0xfc, 0x32, 0x4b, 0x38, 0xe9, 0xae, 0xc9, 0x5a, 0x83, 0xec, 0xd7, 0x65, 0x49, 0x11, 0x65, 0x5f, 0xda, 0xc, 0xf5, 0xbc, 0xd5, 0x95, 0xc7, 0x1a, 0x79, 0xd2, 0x1c, 0xa8, 0x6c, 0x64, 0xaa, 0xe4, 0xc3, 0x8e, 0x4e, 0xea, 0x92, 0xb2, 0xf1, 0x1d, 0x5, 0xc9, 0xea, 0xc4, 0xef, 0xca, 0xef, 0x48, 0x27, 0x6b, 0xc3, 0xaf, 0xe8, 0x90, 0x3, 0xde, 0xb4, 0x8d, 0xbc, 0x70, 0x81, 0x44, 0x3a, 0xa1, 0x1b, 0xb4, 0xf, 0xa9, 0xe4, 0x2a, 0x55, 0xfa, 0x81, 0x9, 0xf6, 0x5d, 0x84, 0xf, 0x59, 0xa2, 0xd1, 0x4, 0x6a, 0x8b, 0x5a, 0x27, 0x40, 0xed, 0x61, 0xcf, 0xdb, 0xc3, 0x2b, 0x2c, 0x98, 0x3e, 0xfc, 0xe5, 0x5b, 0xf6, 0x16, 0xaa, 0x2d, 0x8b, 0x7c, 0xe, 0x94, 0x12, 0x9d, 0x5e, 0x1c, 0x27, 0x7, 0x1b, 0x95, 0x1, 0x26, 0xcb, 0xfa, 0x7e, 0xc, 0xef, 0xa7, 0xcd, 0x93, 0x23, 0xcd, 0xb1, 0x6, 0x17, 0xc0, 0x43, 0x6c, 0xd6, 0xe4, 0xe9, 0x3, 0xc9, 0x62, 0x98, 0xe3, 0x32, 0xe2, 0xa7, 0xe5, 0x4, 0xa3, 0xc0, 0x1, 0x82, 0xdf, 0xb2, 0x47, 0xd0, 0x67, 0xba, 0x8e, 0xdf, 0x3c, 0x43, 0x5c, 0xca, 0x53, 0x9c, 0x15, 0xdd, 0x53, 0x74, 0x50, 0x97, 0x6a, 0x30, 0x45, 0x2b, 0xa2, 0xa7, 0xc0, 0xe7, 0x2, 0x51, 0x82, 0x2e, 0x0, 0x73, 0xbc, 0x28, 0x80, 0xc7, 0x2c, 0x90, 0x44, 0x54, 0x44, 0x6b, 0xe8, 0x77, 0xd9, 0x97, 0x29, 0xbf, 0x6c, 0x62, 0x68, 0x1f, 0x84, 0x1, 0xba, 0xaf, 0x10, 0x79, 0x78, 0x96, 0xf0, 0x5f, 0xbc, 0x34, 0x30, 0xeb, 0x40, 0x4a, 0xde, 0x2f, 0xba, 0x6b, 0xf5, 0x72, 0x26, 0x5b, 0xee, 0xe5, 0x56, 0x4d, 0x9d, 0xd2, 0xae, 0x27, 0x6a, 0xd5, 0x2d, 0xab, 0x3a, 0xaa, 0x77, 0x57, 0xd, 0xa6, 0xe7, 0x43, 0x21, 0xa5, 0xc4, 0x6c, 0xd1, 0xbe, 0x4c, 0x29, 0x21, 0xc9, 0x46, 0x83, 0xf, 0xc8, 0x83, 0xc4, 0x5a, 0xa8, 0x52, 0xde, 0xb2, 0x8a, 0xe7, 0x64, 0xca, 0x28, 0x93, 0x26, 0x80, 0x88, 0x48, 0x22, 0x69, 0xf, 0x98, 0xa5, 0xd1, 0x6, 0x43, 0xa8, 0xd7, 0xad, 0x9d, 0xc9, 0xf4, 0x73, 0x69, 0x62, 0x38, 0xa8, 0xed, 0xa2, 0xe4, 0xdb, 0xb8, 0x22, 0x22, 0x8f, 0x2f, 0xd, 0x37, 0xf1, 0xa6, 0x50, 0x98, 0xc9, 0x1a, 0x6f, 0x46, 0x20, 0xe0, 0xe1, 0x75, 0x2c, 0xe, 0xca, 0xb8, 0x78, 0xbd, 0xa9, 0xb, 0x77, 0x84, 0x1f, 0xdf, 0xa, 0x97, 0x35, 0x47, 0xee, 0x57, 0x7e, 0x3d, 0x7a, 0x15, 0x93, 0xc, 0xa3, 0xb9, 0x39, 0x8a, 0x3e, 0x15, 0x45, 0x6d, 0xf6, 0x40, 0xd5, 0x11, 0xa3, 0xf, 0x5b, 0xe6, 0x92, 0xd8, 0x96, 0xaf, 0x9c, 0x57, 0xeb, 0xae, 0x34, 0xc6, 0x55, 0xef, 0x1, 0x9a, 0xa9, 0x1, 0xa2, 0x23, 0x63, 0x89, 0x7, 0xe, 0xab, 0xb1, 0x9, 0x3f, 0x32, 0xea, 0x19, 0x36, 0x85, 0xe1, 0xb, 0x47, 0x83, 0x35, 0x4e, 0x95, 0xc6, 0x8b, 0x75, 0x9, 0x65, 0xf2, 0x98, 0x69, 0xdb, 0xc5, 0x3a, 0x4f, 0xe1, 0x29, 0xf6, 0xd0, 0x5a, 0x25, 0x57, 0xe0, 0x2a, 0xbc, 0xe0, 0x37, 0x2e, 0xe8, 0xef, 0x69, 0x8e, 0x52, 0xaf, 0xde, 0x6c, 0x59, 0xbc, 0x9, 0x13, 0xf8, 0x80, 0x23, 0xea, 0x56, 0x18, 0x6b, 0x30, 0xc1, 0xa2, 0xa, 0x4c, 0xd4, 0xa, 0xe9, 0x4d, 0x39, 0x38, 0xd8, 0xaf, 0x26, 0xd, 0x36, 0x52, 0xc, 0x1e, 0x51, 0x40, 0x47, 0x25, 0x32, 0x70, 0xec, 0xc8, 0x13, 0x56, 0x93, 0x76, 0xa6, 0xc3, 0x38, 0xaa, 0xb3, 0x80, 0x32, 0x8e, 0x12, 0xf, 0x82, 0x84, 0xf5, 0x58, 0x9a, 0x53, 0x70, 0xd4, 0x31, 0xcc, 0x79, 0xeb, 0xb7, 0xb1, 0xa5, 0x96, 0x9f, 0xcf, 0xb9, 0xf9, 0xd6, 0xad, 0x5e, 0xa7, 0xc7, 0xbe, 0xd5, 0xea, 0x92, 0xca, 0x29, 0xdd, 0xbe, 0x7c, 0x9b, 0x8b, 0xa5, 0x80, 0x7f, 0xd7, 0xc5, 0x75, 0xeb, 0xa1, 0x5, 0x3a, 0x25, 0x30, 0xb0, 0xcf, 0xe4, 0x79, 0x23, 0x13, 0xea, 0x4b, 0x71, 0x59, 0x53, 0x1b, 0x8, 0x5b, 0xb0, 0x35, 0xae, 0x3a, 0x60, 0x4a, 0x53, 0x8b, 0x36, 0x44, 0x41, 0x96, 0xeb, 0x7d, 0x9b, 0x89, 0xef, 0x4e, 0xf7, 0x65, 0x68, 0xfe, 0x80, 0x75, 0xe5, 0xcb, 0x90, 0xfd, 0x1, 0xae, 0xaf, 0x55, 0xa4, 0x7e, 0x29, 0xad, 0xa3, 0xd, 0xa3, 0x80, 0x6e, 0x84, 0x49, 0x93, 0x6f, 0x17, 0xfa, 0xda, 0x9a, 0xb6, 0x9a, 0xa1, 0xcd, 0x61, 0x79, 0x48, 0x5f, 0xd0, 0x48, 0x22, 0xb5, 0x23, 0xba, 0xc9, 0x60, 0x1e, 0x92, 0xb5, 0x2f, 0xd5, 0xbb, 0xa0, 0x76, 0x2a, 0xc5, 0x8f, 0x16, 0x57, 0x34, 0x6d, 0xae, 0x65, 0xbf, 0x7e, 0x8f, 0x53, 0x5a, 0xb, 0xc8, 0x48, 0xce, 0x8d, 0x46, 0xd4, 0x2b, 0x93, 0x50, 0x63, 0x88, 0xf1, 0x9a, 0x4c, 0x73, 0x24, 0x22, 0xaf, 0xee, 0x6a, 0x20, 0x45, 0x91, 0xc3, 0x3c, 0xbe, 0xeb, 0x28, 0x1f, 0xae, 0x1, 0x46, 0xd0, 0x42, 0xbc, 0x68, 0xf9, 0x53, 0x60, 0x9c, 0x40, 0xfd, 0xb6, 0x46, 0x63, 0xf8, 0x15, 0xeb, 0x84, 0x6c, 0xdb, 0x9a, 0x55, 0x9e, 0x63, 0x77, 0xa6, 0x4f, 0xaf, 0xc0, 0xeb, 0x47, 0x81, 0x3, 0xd5, 0x19, 0xfa, 0x32, 0x80, 0xc0, 0xac, 0x2a, 0xab, 0x9f, 0xda, 0xad, 0xd0, 0x78, 0x51, 0x82, 0x2d, 0x40, 0xd8, 0x73, 0x95, 0xea, 0xc3, 0x22, 0x9e, 0xd2, 0xad, 0x6c, 0x6c, 0xe7, 0x9f, 0xad, 0xcf, 0x7, 0x2b, 0xb4, 0x9b, 0x28, 0xa5, 0x6f, 0x92, 0x99, 0x31, 0x8d, 0xd7, 0xae, 0xe4, 0x92, 0xcf, 0x5, 0x12, 0x5b, 0x60, 0x38, 0x67, 0x56, 0x91, 0x8f, 0x39, 0x3d, 0x90, 0xbd, 0x0, 0x6c, 0xdb, 0xef, 0xab, 0xb0, 0x69, 0x67, 0xe7, 0x6c, 0x23, 0xde, 0x3b, 0x6e, 0x1a, 0xff, 0x10, 0xcf, 0x1, 0x1c, 0x7, 0x43, 0x8f, 0x31, 0x10, 0x5d, 0xe1, 0x9f, 0xb5, 0xc3, 0xa0, 0xcc, 0xec, 0xd8, 0x16, 0x1e, 0xd0, 0xf8, 0x48, 0x8e, 0x3a, 0x93, 0xc3, 0xcc, 0xea, 0x71, 0x55, 0x67, 0xb, 0x7c, 0x12, 0xf, 0xfe, 0x45, 0xc3, 0x2b, 0x61, 0x2f, 0x1f, 0xa0, 0x97, 0x83, 0x30, 0x46, 0x83, 0x74, 0xe4, 0x1, 0xcb, 0xd6, 0x63, 0x5b, 0x0, 0x73, 0x4b, 0x59, 0x6, 0xd, 0x13, 0xd6, 0xea, 0xfb, 0x1a, 0xdd, 0xb, 0xe8, 0xbb, 0xbe, 0x39, 0xb6, 0x51, 0x8d, 0xcb, 0xee, 0x94, 0xa1, 0xb3, 0xed, 0x46, 0x3a, 0xf, 0xce, 0xb2, 0xe5, 0x12, 0xc4, 0xad, 0x9f, 0xcb, 0xf8, 0x92, 0xa7, 0x18, 0xbd, 0x5e, 0x98, 0x22, 0xa3, 0xe4, 0xab, 0x7f, 0x30, 0x44, 0x4c, 0xaf, 0x79, 0x5d, 0x4c, 0xfc, 0xd6, 0x5, 0x8d, 0x9f, 0x5b, 0xd, 0xac, 0x45, 0x74, 0xe1, 0xaf, 0xf1, 0xc5, 0x96, 0x39, 0xfe, 0xc9, 0xe1, 0xd7, 0x12, 0x3d, 0x52, 0xe7, 0xf8, 0x7, 0xe4, 0xd6, 0xfc, 0xb4, 0x89, 0x9b, 0x8e, 0x8e, 0x27, 0x39, 0x89, 0xb3, 0x7e, 0xd1, 0xe3, 0xc1, 0xd1, 0xf1, 0xd6, 0x4, 0x76, 0xd8, 0x40, 0xbc, 0x24, 0xe5, 0x83, 0xaf, 0x8c, 0x9, 0xf9, 0xd0, 0x4e, 0x3a, 0xb8, 0x82, 0x2a, 0xe9, 0xe0, 0x9a, 0x5d, 0x29, 0x3b, 0x5f, 0x6b, 0x1, 0x1a, 0x46, 0xc0, 0xec, 0x7a, 0x57, 0x29, 0x65, 0x3c, 0xcc, 0xae, 0xcc, 0xe7, 0x71, 0x9a, 0x4d, 0xc9, 0x57, 0xe0, 0xf4, 0xf2, 0x38, 0x4b, 0x69, 0xa3, 0x6e, 0x26, 0x1e, 0xc7, 0xec, 0x2c, 0xa7, 0xec, 0x98, 0xd9, 0xac, 0x36, 0xa9, 0xee, 0x2a, 0x28, 0xb2, 0xd9, 0x4c, 0x1b, 0x46, 0x77, 0x15, 0xa4, 0x5c, 0x51, 0xe, 0x39, 0xa0, 0xce, 0x62, 0x90, 0xc9, 0x2a, 0x34, 0xa7, 0x7e, 0xb1, 0x73, 0x90, 0xb6, 0xc5, 0xb5, 0xa8, 0xf1, 0xd9, 0xee, 0xe1, 0x36, 0xac, 0xc4, 0xeb, 0x3a, 0xdd, 0x3, 0xb7, 0x8d, 0xbe, 0x8d, 0x1a, 0x5d, 0x53, 0xb0, 0xac, 0xc7, 0x59, 0x62, 0x9a, 0x70, 0xbb, 0x8a, 0x9b, 0x36, 0xde, 0x6c, 0x29, 0x3c, 0x1a, 0x12, 0x26, 0x88, 0x31, 0x4d, 0xc, 0x3, 0xe6, 0x18, 0x3f, 0xd, 0x3, 0xec, 0xce, 0x33, 0x65, 0xd9, 0x69, 0x8b, 0x21, 0x87, 0x88, 0x77, 0x6, 0xd4, 0x3e, 0x23, 0xf0, 0xe, 0x6b, 0x48, 0x67, 0x20, 0xc7, 0x85, 0x26, 0xb9, 0x6, 0xb9, 0x57, 0x20, 0xdb, 0x70, 0x7, 0x2, 0xde, 0x6, 0x12, 0x85, 0xb, 0xcb, 0x93, 0xbc, 0x61, 0xd1, 0xaa, 0x84, 0x68, 0x39, 0x4d, 0xa5, 0xf7, 0xf2, 0xd5, 0x91, 0x31, 0x4e, 0x8b, 0x61, 0xad, 0x92, 0x9, 0x13, 0x27, 0x2b, 0x5, 0xf0, 0xc9, 0x6f, 0x79, 0x8a, 0xfe, 0x7f, 0x39, 0x21, 0x9, 0xfa, 0xb, 0x8, 0x95, 0x87, 0x1b, 0xb0, 0x94, 0x3f, 0xc1, 0x3b, 0xc2, 0x20, 0xc5, 0x2f, 0x6a, 0xf0, 0x86, 0x55, 0xb, 0x57, 0x3b, 0x80, 0xe8, 0x1d, 0x20, 0x46, 0x60, 0xe3, 0xb1, 0xe5, 0xc9, 0xcb, 0xaa, 0xe2, 0x11, 0xd0, 0xae, 0x4f, 0xfe, 0xf4, 0xc5, 0x45, 0x3c, 0xef, 0x7e, 0x2d, 0xda, 0x60, 0x28, 0x61, 0x58, 0xe8, 0xce, 0xf6, 0xed, 0xb3, 0x2f, 0xd, 0x81, 0xc2, 0x96, 0x9a, 0xc, 0xb5, 0x18, 0xda, 0x54, 0xb, 0x79, 0xd0, 0x61, 0x1d, 0x6f, 0xd8, 0x20, 0x97, 0xd1, 0xfd, 0x4d, 0x8a, 0x91, 0xd7, 0x31, 0xad, 0x85, 0x41, 0x60, 0xae, 0x7f, 0x61, 0x78, 0xb1, 0xd2, 0x36, 0x8, 0xd6, 0x96, 0xf9, 0xd6, 0x48, 0x80, 0x8d, 0xc9, 0x49, 0x19, 0x6e, 0x54, 0x16, 0xbe, 0xdc, 0xca, 0xa0, 0xba, 0x23, 0x1f, 0x78, 0x81, 0xda, 0xcd, 0xeb, 0xac, 0x99, 0x7b, 0x3e, 0x29, 0xfc, 0x5d, 0xd9, 0x41, 0x78, 0x63, 0xba, 0x89, 0xa1, 0xc9, 0x4e, 0xec, 0x2f, 0x99, 0xf6, 0xae, 0xc3, 0x47, 0x57, 0x85, 0x5f, 0x6, 0x66, 0x95, 0xa6, 0xf9, 0x33, 0x26, 0xb4, 0x2d, 0x47, 0xb, 0xd4, 0x9c, 0xeb, 0xda, 0x32, 0x36, 0x29, 0xb3, 0x7a, 0x60, 0x19, 0x45, 0xac, 0x1a, 0x1b, 0x81, 0xbc, 0x4a, 0x68, 0xa0, 0x90, 0xe2, 0x86, 0x40, 0x25, 0xa9, 0xef, 0xa1, 0x1b, 0xff, 0x5e, 0x5e, 0x54, 0x7b, 0xd0, 0xe5, 0x65, 0x96, 0x62, 0x48, 0xfa, 0x62, 0x4d, 0x10, 0xb0, 0x27, 0xa0, 0x6d, 0xaf, 0x2c, 0xf6, 0xb2, 0x6a, 0xf, 0x18, 0x96, 0xfc, 0xa3, 0x6a, 0x6f, 0xca, 0x79, 0xbe, 0xb7, 0xe6, 0x73, 0xd4, 0xd8, 0xae, 0x31, 0x14, 0x8e, 0x16, 0x63, 0x51, 0x33, 0x21, 0x39, 0x4f, 0x6b, 0xc3, 0x63, 0xc5, 0xae, 0xb6, 0x94, 0x8, 0xce, 0x9d, 0x96, 0xaf, 0xc9, 0xc5, 0x18, 0x21, 0x4e, 0x68, 0x16, 0x64, 0xa3, 0x77, 0x2b, 0x17, 0x48, 0xe2, 0xaf, 0x8a, 0xb5, 0xf3, 0x9e, 0xaf, 0x9a, 0x34, 0xf1, 0x26, 0x79, 0x9c, 0x56, 0x42, 0xf9, 0x21, 0x39, 0x1b, 0xf8, 0x29, 0x4f, 0x4c, 0x18, 0x1b, 0xe2, 0x96, 0xc8, 0xd4, 0xaa, 0x8, 0x7c, 0x27, 0xa1, 0xe3, 0xd0, 0x88, 0x92, 0x51, 0x21, 0x1d, 0x4, 0xa5, 0xd0, 0x62, 0x64, 0xc9, 0x3f, 0xb2, 0xa9, 0xcd, 0x2a, 0x8d, 0x2b, 0xe7, 0x70, 0x1b, 0x72, 0x42, 0x26, 0x85, 0x41, 0x39, 0xcc, 0x4c, 0x8c, 0x1a, 0xc3, 0x4d, 0xc9, 0xbf, 0x51, 0xa5, 0x18, 0x2f, 0xd1, 0x72, 0xb5, 0x8e, 0xf3, 0xe6, 0x1b, 0x7c, 0xa6, 0xf3, 0xa7, 0x43, 0xe, 0x11, 0xe, 0xb8, 0x91, 0x5f, 0xf5, 0xcd, 0xae, 0x0, 0x7a, 0xf, 0xb3, 0x9e, 0x9d, 0xd2, 0xe8, 0xca, 0xa6, 0x3b, 0xed, 0xa5, 0xb9, 0x91, 0x34, 0xf, 0x39, 0x35, 0xfa, 0xb8, 0xde, 0xd2, 0xd3, 0xa4, 0xc2, 0x10, 0xb2, 0xbd, 0x92, 0x52, 0xbe, 0x90, 0x4f, 0x1a, 0x13, 0x36, 0x51, 0x30, 0xa0, 0x9d, 0x0, 0xf8, 0x40, 0x58, 0x55, 0x37, 0xb3, 0xfc, 0x1b, 0xf9, 0xf6, 0x3c, 0xba, 0xec, 0x65, 0x39, 0x19, 0xd2, 0x86, 0x2e, 0xd3, 0x6b, 0xe1, 0xdb, 0x99, 0x55, 0x9f, 0xc2, 0x6, 0x51, 0xa6, 0x40, 0xca, 0x62, 0xa6, 0x6b, 0xfa, 0x1e, 0x9b, 0x46, 0xbc, 0x78, 0x11, 0x2f, 0x57, 0xa6, 0x61, 0xcb, 0x2c, 0x12, 0xd1, 0x2e, 0xf9, 0xa4, 0xb6, 0x55, 0x66, 0x78, 0xf7, 0x8c, 0x38, 0xd8, 0xf5, 0x4, 0xa2, 0x1c, 0xa2, 0xf2, 0x38, 0x50, 0xee, 0xba, 0xe3, 0xa6, 0x9a, 0x33, 0x5e, 0xcb, 0xe7, 0xeb, 0xaf, 0x98, 0xec, 0xc3, 0x18, 0x1d, 0x1b, 0x32, 0xc3, 0xcc, 0xdb, 0xd2, 0x19, 0x32, 0xc5, 0x93, 0x8b, 0x40, 0x5, 0x52, 0xe9, 0xa5, 0x99, 0x74, 0xa9, 0x8e, 0xfc, 0xae, 0x56, 0x11, 0x88, 0xcc, 0xef, 0xa4, 0x8a, 0x0, 0xe9, 0xb6, 0x51, 0xb3, 0x96, 0x3, 0x44, 0x96, 0xd1, 0xbe, 0x8f, 0x36, 0xd1, 0xb8, 0x3f, 0xf, 0xd7, 0x89, 0x63, 0x2b, 0x76, 0xad, 0xbf, 0xc3, 0x44, 0x5e, 0x9c, 0x38, 0x84, 0x16, 0xb4, 0xbd, 0xc6, 0xbb, 0x19, 0x68, 0x93, 0xd4, 0xc2, 0xa7, 0x6a, 0x98, 0x80, 0x90, 0xa8, 0xe, 0xbd, 0x42, 0x83, 0x1f, 0x27, 0x22, 0x7, 0xba, 0xa3, 0x74, 0x10, 0x3b, 0xf8, 0x40, 0x59, 0xba, 0xcb, 0x5a, 0x64, 0xc, 0x2e, 0x76, 0x17, 0xab, 0xa9, 0x5c, 0x59, 0x93, 0xcc, 0xbf, 0x9f, 0x59, 0xfb, 0x9d, 0x1f, 0x1c, 0x14, 0x3b, 0xc1, 0xda, 0xd8, 0xb6, 0x7a, 0x48, 0x3d, 0xdf, 0x1a, 0x49, 0xbf, 0x91, 0xd, 0x12, 0xd, 0x88, 0x3f, 0x7e, 0xb3, 0xcf, 0x7e, 0x73, 0x88, 0x50, 0xae, 0xd7, 0x4c, 0x1b, 0x37, 0xce, 0x51, 0xaf, 0xb6, 0x76, 0x83, 0xc3, 0xa9, 0x4f, 0x55, 0xaf, 0x36, 0x63, 0x83, 0xe4, 0x6d, 0x13, 0xfe, 0x2c, 0xe2, 0x4b, 0xf0, 0x96, 0x59, 0xf0, 0x96, 0x75, 0xc1, 0x9b, 0x31, 0x5c, 0xd6, 0x98, 0x15, 0xb3, 0xe6, 0xbc, 0xa3, 0xd, 0x63, 0x36, 0x76, 0x9d, 0x56, 0x8b, 0x18, 0x5f, 0x3c, 0xb3, 0xa0, 0x39, 0xdb, 0xd, 0xcd, 0xd9, 0x2e, 0x68, 0xce, 0xba, 0xa1, 0x39, 0x53, 0xd0, 0x2c, 0x1a, 0xf8, 0x2b, 0x80, 0x60, 0xe4, 0x4d, 0xf9, 0x25, 0x47, 0x1f, 0x58, 0x6a, 0x7, 0xdd, 0xb0, 0xa9, 0xad, 0x83, 0x83, 0xcc, 0x80, 0x78, 0x4, 0xf8, 0xfa, 0xc6, 0xc2, 0x81, 0x81, 0x1a, 0xc7, 0xde, 0x3e, 0xe5, 0x2c, 0x33, 0x5d, 0xcc, 0x8f, 0x95, 0xb3, 0xfc, 0x55, 0x3f, 0x53, 0x2a, 0xe6, 0xab, 0x5e, 0xa6, 0x7c, 0xd7, 0xa7, 0xc0, 0xa7, 0xf5, 0xfd, 0xfa, 0x53, 0x2c, 0x29, 0x4a, 0xd7, 0xcd, 0x99, 0x1e, 0x1d, 0x8f, 0x5b, 0x83, 0xf6, 0x79, 0x2f, 0x2a, 0x58, 0xd9, 0x87, 0x7f, 0x72, 0xf8, 0xc2, 0x73, 0x6b, 0x23, 0x98, 0x1d, 0x27, 0xfd, 0xd7, 0x20, 0x10, 0x79, 0x3d, 0x23, 0xf7, 0x16, 0x7, 0x6e, 0x5c, 0x81, 0x70, 0x66, 0x5e, 0xa2, 0x94, 0x8d, 0x5f, 0x56, 0xd, 0x85, 0x6d, 0x9a, 0xf3, 0x32, 0xd0, 0x8f, 0x7a, 0x72, 0xbd, 0x83, 0x1e, 0x1b, 0x8b, 0xb6, 0xed, 0x20, 0x7, 0xb5, 0x59, 0xa2, 0xdc, 0x7, 0x73, 0x77, 0xa0, 0xaf, 0x13, 0xb5, 0x29, 0x76, 0x7a, 0x26, 0xcb, 0x5f, 0xc3, 0xe7, 0x49, 0xbd, 0x59, 0x92, 0xf9, 0x15, 0xb8, 0xe3, 0x1d, 0x61, 0x43, 0x89, 0x84, 0x63, 0x79, 0xe3, 0xf6, 0x9d, 0xd8, 0xf8, 0x99, 0x96, 0xd4, 0xf5, 0x2f, 0x21, 0x20, 0xab, 0x9f, 0x42, 0xe8, 0x91, 0xeb, 0x74, 0xf5, 0x70, 0x99, 0xcd, 0x1, 0x90, 0x13, 0x7a, 0xf5, 0x40, 0x42, 0xf2, 0xb5, 0x4c, 0x8c, 0xa7, 0xe8, 0x84, 0x6e, 0xdd, 0x7c, 0xa0, 0xec, 0x22, 0x5, 0xb6, 0x88, 0x80, 0xd1, 0xba, 0xbf, 0x93, 0xcf, 0x7f, 0x5f, 0x55, 0xf2, 0x1e, 0xaf, 0x77, 0x7c, 0x28, 0x7a, 0x51, 0x32, 0x9e, 0x4, 0x59, 0x35, 0x46, 0x95, 0xaf, 0x4, 0x44, 0xf4, 0x28, 0xee, 0xd5, 0x1d, 0x9, 0x21, 0xaa, 0x97, 0x8d, 0xe5, 0x92, 0xf2, 0xa3, 0xe3, 0x96, 0x1e, 0x68, 0x62, 0x4d, 0x83, 0xde, 0xd9, 0x95, 0x68, 0xaf, 0xf, 0xc5, 0x4f, 0x86, 0x4a, 0x55, 0xab, 0x4a, 0xac, 0x85, 0x86, 0x58, 0x4e, 0xb4, 0x9f, 0xd7, 0x25, 0xd4, 0xac, 0x41, 0x12, 0x2f, 0xde, 0x78, 0x4a, 0x93, 0x5b, 0xb7, 0xc5, 0xa4, 0xce, 0x11, 0x2a, 0x91, 0xcb, 0xf2, 0x8e, 0xe3, 0x40, 0x63, 0x24, 0x11, 0x2b, 0x30, 0xbe, 0x5, 0x97, 0x47, 0xae, 0x24, 0x37, 0xe5, 0x9b, 0xac, 0x52, 0xba, 0x41, 0xd1, 0x71, 0x70, 0x93, 0x0, 0x40, 0xc8, 0x35, 0xf, 0x3b, 0xae, 0x30, 0x2d, 0x54, 0xd9, 0xcf, 0x8c, 0xb3, 0x60, 0x42, 0x9d, 0xb1, 0x78, 0xaa, 0xa8, 0x9f, 0xb5, 0xb2, 0x82, 0x56, 0xed, 0xfe, 0xbb, 0xd6, 0xb6, 0x99, 0x8, 0x71, 0xfe, 0xc6, 0xc2, 0x19, 0x86, 0x26, 0x23, 0x96, 0x32, 0x54, 0xb, 0xd7, 0xcb, 0x1c, 0xe3, 0xbb, 0xc7, 0x44, 0x7b, 0xf7, 0x9f, 0xa8, 0xa3, 0x8b, 0x7b, 0x4f, 0xb3, 0xa3, 0xae, 0x6b, 0x92, 0x5b, 0x73, 0xff, 0xae, 0xcc, 0xfd, 0x13, 0x10, 0x58, 0xc3, 0x8d, 0xa4, 0xf3, 0xa6, 0xa8, 0xdf, 0xee, 0xc5, 0x5c, 0x33, 0x1, 0xa0, 0x75, 0xb, 0xf7, 0xa9, 0xbf, 0x7d, 0x44, 0xb2, 0x5a, 0x4c, 0x57, 0xe0, 0xad, 0xf2, 0x26, 0x6e, 0x6c, 0x2, 0xad, 0x56, 0xa6, 0x40, 0x16, 0x7e, 0x37, 0xd1, 0x1, 0x25, 0xa2, 0xf8, 0x8f, 0x2b, 0x18, 0x79, 0x17, 0x59, 0x9a, 0x2e, 0xb9, 0x27, 0xdb, 0xb1, 0xcf, 0x3c, 0x2b, 0x7a, 0x74, 0x4a, 0x7a, 0xe5, 0xd1, 0xb1, 0x62, 0xf4, 0x4c, 0xfd, 0xab, 0x93, 0xe3, 0x73, 0x9, 0x66, 0x1a, 0x45, 0xbc, 0x1f, 0x4a, 0xd3, 0x9a, 0x40, 0x55, 0xdd, 0x52, 0xd, 0x36, 0xca, 0x18, 0xd, 0x35, 0xf4, 0x94, 0xb2, 0x35, 0xf3, 0x2, 0x4c, 0x68, 0x1, 0xe5, 0x5d, 0xc4, 0xa1, 0x8d, 0xc9, 0xfc, 0x76, 0x9, 0xb4, 0x6d, 0xb5, 0x27, 0x0, 0xb, 0xd3, 0x44, 0x79, 0x3d, 0x74, 0xc5, 0xeb, 0x1a, 0x26, 0xda, 0x71, 0xd0, 0x42, 0xd8, 0x5, 0xc6, 0x36, 0x8b, 0xe0, 0x40, 0xc1, 0x58, 0x52, 0xe2, 0x60, 0x60, 0x20, 0xde, 0xfa, 0x9a, 0x9b, 0xd0, 0xc3, 0x61, 0xc6, 0x78, 0x83, 0x9e, 0x3d, 0x97, 0x8f, 0x49, 0xf, 0x7f, 0x96, 0xb1, 0xea, 0x5c, 0x6, 0x86, 0x53, 0x16, 0x32, 0xd, 0x7c, 0x2e, 0x6d, 0x3c, 0x8c, 0x85, 0x52, 0x7c, 0xc5, 0x75, 0xbf, 0x3c, 0x19, 0xa, 0xdc, 0x7c, 0x1d, 0x95, 0x8a, 0xe3, 0x2c, 0x4f, 0x5b, 0x17, 0x89, 0x1a, 0xfb, 0xb6, 0xef, 0x18, 0xfb, 0x4a, 0xbc, 0xbf, 0x72, 0x69, 0xff, 0xe5, 0xf1, 0x90, 0xc7, 0x44, 0x68, 0xd9, 0xd, 0xa2, 0xab, 0x78, 0x5f, 0x2b, 0x1f, 0x2f, 0x5f, 0x2b, 0xc, 0x59, 0xf3, 0x79, 0x83, 0xd, 0xb0, 0x99, 0xdd, 0xeb, 0xbe, 0x35, 0xa3, 0x9e, 0x4d, 0xa3, 0xe0, 0xe4, 0xf4, 0x1b, 0x26, 0xe1, 0x12, 0x71, 0x58, 0x3b, 0x78, 0x74, 0x1c, 0x66, 0x3d, 0x5f, 0xef, 0xae, 0x5a, 0xdc, 0x43, 0xde, 0x6b, 0x81, 0x84, 0x1b, 0x4, 0xba, 0x5, 0xc2, 0xdd, 0xa4, 0xe5, 0x51, 0x63, 0xb7, 0x35, 0xb9, 0xb0, 0x26, 0xc5, 0xea, 0xa5, 0x32, 0x1, 0xdd, 0x81, 0x3d, 0xc6, 0x2d, 0xb1, 0xf3, 0x3e, 0x12, 0x9f, 0x8d, 0x35, 0xd, 0xd4, 0x42, 0x8, 0xf2, 0xe, 0xc4, 0x62, 0x22, 0x28, 0xeb, 0xbe, 0x81, 0x55, 0xae, 0xf3, 0xd0, 0x46, 0x47, 0x98, 0xc3, 0x4c, 0x4a, 0xa1, 0x39, 0x10, 0x15, 0xb9, 0xb0, 0x86, 0x2, 0x7f, 0x48, 0xb4, 0xac, 0x6e, 0x97, 0x8e, 0x87, 0x79, 0x79, 0x27, 0x4e, 0x49, 0xc3, 0xf4, 0x6e, 0x27, 0x2a, 0xd5, 0xc3, 0xc9, 0x9c, 0xa3, 0x68, 0x9d, 0x37, 0xc7, 0xa8, 0x78, 0x6f, 0x14, 0x38, 0x10, 0xb6, 0xf3, 0xc6, 0x41, 0x16, 0x23, 0x6b, 0xaf, 0xfb, 0xce, 0x1a, 0xdb, 0xef, 0x37, 0x40, 0x91, 0x75, 0xa1, 0x5b, 0xf8, 0xb5, 0x7b, 0x2c, 0xa8, 0xb, 0xa2, 0xec, 0x7f, 0xc9, 0x50, 0xb6, 0x4a, 0x2d, 0x49, 0x44, 0x46, 0x18, 0xa, 0xbe, 0x1b, 0x75, 0xa1, 0x80, 0x95, 0x6c, 0xba, 0xc9, 0x96, 0xe9, 0xf, 0x32, 0x5c, 0x55, 0xb3, 0xcc, 0xb5, 0x74, 0xc3, 0x3c, 0x3b, 0xd7, 0xce, 0xce, 0x55, 0x74, 0x29, 0xdf, 0x41, 0x54, 0x8e, 0xb9, 0x78, 0x49, 0x39, 0x1c, 0x2b, 0x96, 0x9e, 0xfc, 0x76, 0xc7, 0x59, 0xaf, 0x17, 0x98, 0x2d, 0x88, 0xbb, 0xd3, 0xc7, 0x8a, 0x52, 0x9a, 0x3e, 0x9a, 0xca, 0xf, 0x53, 0xe4, 0x5d, 0x64, 0x79, 0x2f, 0x3b, 0x6c, 0x74, 0x30, 0xa8, 0x8a, 0xcf, 0xb2, 0x2b, 0x9e, 0x52, 0xf4, 0x11, 0x89, 0x8e, 0x45, 0xc3, 0x86, 0x40, 0x25, 0x55, 0x44, 0xf2, 0x6e, 0xbd, 0xd4, 0x31, 0xb8, 0x26, 0xdd, 0xa8, 0x5f, 0xe, 0x2e, 0x8, 0xf1, 0x55, 0x83, 0x34, 0xfd, 0x5e, 0x44, 0xe9, 0x6a, 0x59, 0x3f, 0x5d, 0x99, 0x73, 0x50, 0x5a, 0x59, 0x1a, 0x74, 0xf9, 0x18, 0x40, 0xaf, 0xea, 0xf5, 0x98, 0xb9, 0xa2, 0xc2, 0x24, 0xa3, 0xd9, 0x58, 0xa3, 0x2d, 0x11, 0x30, 0xa6, 0xdd, 0x56, 0xbf, 0x6f, 0xb5, 0x5, 0x7f, 0x5a, 0x4d, 0x90, 0xe4, 0x2f, 0x74, 0x79, 0xe6, 0xc4, 0x27, 0x16, 0x7c, 0x84, 0x43, 0xad, 0x34, 0xe8, 0x2a, 0x2a, 0x29, 0x4c, 0xb, 0x3d, 0xf7, 0x1f, 0x84, 0x2d, 0x6c, 0x58, 0xf7, 0x29, 0xa9, 0xc9, 0xca, 0x4, 0x65, 0xd5, 0x49, 0xdf, 0xca, 0x1b, 0x4b, 0x3, 0x81, 0xc8, 0x2e, 0xd3, 0x68, 0x8f, 0x0, 0x4b, 0x72, 0x73, 0xd2, 0xa1, 0xff, 0x7, 0x12, 0x3a, 0x55, 0x8c, 0xe3, 0x81, 0x9, 0xa1, 0x6a, 0xc5, 0x74, 0x59, 0xb1, 0xcc, 0xcf, 0x8a, 0x4a, 0x3e, 0x89, 0x3d, 0xce, 0x4e, 0x77, 0x77, 0x17, 0xdc, 0x31, 0x1e, 0x26, 0x97, 0xca, 0x80, 0x2f, 0xf6, 0x4e, 0xc3, 0x3b, 0x69, 0x56, 0x97, 0x10, 0xd9, 0x39, 0xe4, 0x2d, 0xeb, 0xc8, 0x6a, 0x1b, 0x36, 0x59, 0xbc, 0xd0, 0x4c, 0xb3, 0x41, 0x68, 0x84, 0xb1, 0x83, 0x15, 0x92, 0x30, 0x87, 0xc6, 0x1d, 0xb5, 0xa1, 0xf0, 0x9d, 0xa5, 0x2d, 0x70, 0x55, 0xdc, 0x9c, 0x6a, 0x61, 0xac, 0xe8, 0xf0, 0x15, 0x61, 0x1e, 0x89, 0xd8, 0x9e, 0x9, 0x43, 0x3b, 0x60, 0x17, 0x24, 0x3a, 0xb7, 0x72, 0xbf, 0x4, 0xaa, 0x17, 0x69, 0xf9, 0xd5, 0x58, 0xa0, 0xde, 0x68, 0x38, 0x41, 0x5e, 0xc1, 0x91, 0xce, 0x8c, 0x51, 0xa8, 0x65, 0x89, 0x64, 0xaa, 0xa5, 0x13, 0xce, 0x59, 0xb1, 0x83, 0xc7, 0x93, 0xd3, 0x90, 0xa8, 0xe3, 0xca, 0x40, 0x1d, 0x85, 0x46, 0x6c, 0x56, 0x7c, 0x88, 0xc6, 0x8e, 0xf9, 0xa, 0x39, 0x1b, 0x49, 0x40, 0x32, 0xfb, 0x9f, 0xb4, 0x1a, 0x3c, 0x8d, 0xc5, 0x73, 0x79, 0x8e, 0x71, 0x4b, 0xfb, 0x9b, 0x46, 0x61, 0x47, 0xc1, 0x93, 0xe8, 0xbf, 0x87, 0xce, 0x8c, 0xd3, 0xe1, 0x38, 0x90, 0x11, 0x43, 0x50, 0x95, 0xf9, 0xdc, 0x77, 0x94, 0x41, 0x82, 0x19, 0xe5, 0x87, 0x1c, 0xce, 0x5d, 0x7e, 0x8, 0x92, 0x50, 0x93, 0xd5, 0x6a, 0xaf, 0xfe, 0x9f, 0xb5, 0x7e, 0xa0, 0xb5, 0x5b, 0xad, 0xda, 0x1, 0xeb, 0xda, 0x75, 0x27, 0xed, 0xb2, 0x87, 0xa6, 0xf0, 0xa4, 0xb9, 0xfe, 0xf9, 0x61, 0x31, 0x76, 0xce, 0x54, 0xd, 0xaa, 0xc6, 0x2d, 0x5a, 0x57, 0xdb, 0x31, 0xef, 0xc3, 0xa2, 0xf7, 0xb1, 0xbc, 0xf0, 0x6f, 0x75, 0x33, 0xdc, 0x3d, 0x6e, 0xb, 0x9b, 0x39, 0x96, 0xc1, 0x28, 0x63, 0x9c, 0x56, 0x81, 0x8, 0xc2, 0x84, 0x98, 0x54, 0xc8, 0x7a, 0x8, 0x12, 0x6c, 0x97, 0x5a, 0xad, 0x46, 0x30, 0x7d, 0x6b, 0x5a, 0x66, 0x73, 0x5d, 0xbc, 0xb8, 0xd1, 0xbc, 0x1f, 0x1c, 0x69, 0x3a, 0x29, 0x1a, 0xba, 0x88, 0xaf, 0x2, 0xfb, 0x7d, 0x53, 0xb5, 0x60, 0xd9, 0xa1, 0xba, 0x7e, 0x81, 0xc2, 0x16, 0x96, 0x71, 0x74, 0xe4, 0x3b, 0x37, 0xc1, 0xe0, 0x90, 0xfb, 0x1d, 0x30, 0xd2, 0xeb, 0x58, 0xd8, 0x0, 0x2d, 0x99, 0xb2, 0x23, 0x15, 0x6, 0xc9, 0x6f, 0x11, 0x3a, 0x5f, 0x3d, 0xf5, 0xc, 0x42, 0xc9, 0x5f, 0xd6, 0x59, 0x8a, 0xcc, 0x10, 0xc6, 0x3f, 0x19, 0x5, 0x18, 0xe1, 0xad, 0x8c, 0xf8, 0xa1, 0xab, 0x6d, 0xec, 0x72, 0xdc, 0x78, 0x2b, 0xda, 0x6c, 0x0, 0xc0, 0xa6, 0xec, 0x45, 0x4, 0xa9, 0x86, 0xa1, 0x6, 0x5a, 0x8b, 0x3a, 0x6e, 0xe, 0xd5, 0x95, 0xb7, 0x7d, 0xdf, 0x2a, 0x49, 0xef, 0x9d, 0x3a, 0x69, 0x7f, 0x27, 0x1d, 0x9, 0x8e, 0x6a, 0x76, 0x8, 0x56, 0xc2, 0x18, 0x8c, 0x7b, 0x52, 0x12, 0x37, 0x69, 0x2e, 0xc6, 0xdf, 0xcd, 0x5c, 0xdb, 0x9c, 0x7a, 0xee, 0x9b, 0xfc, 0x4c, 0xcd, 0xa5, 0x1b, 0x8e, 0x66, 0x4d, 0xd8, 0x28, 0xd8, 0xc2, 0x1c, 0x54, 0x1c, 0xb0, 0x65, 0xa4, 0x39, 0xa7, 0xcf, 0x8b, 0x75, 0xf6, 0x16, 0x1a, 0x8e, 0x97, 0xb4, 0xa8, 0x63, 0x4b, 0x7a, 0x11, 0xda, 0x99, 0x6e, 0xf1, 0xc5, 0x66, 0xbf, 0x50, 0xf7, 0xac, 0x45, 0x81, 0x9c, 0xf1, 0x3e, 0x20, 0x75, 0xe8, 0xc, 0xe3, 0x5b, 0x17, 0xb7, 0xb7, 0xf8, 0x72, 0xd2, 0x12, 0x2d, 0x36, 0xd9, 0x12, 0xb, 0x9a, 0x7a, 0xb0, 0xe2, 0x74, 0x88, 0xa6, 0xb4, 0xd, 0xb5, 0xf9, 0x5c, 0x6e, 0xb4, 0x52, 0x9c, 0xb7, 0x94, 0xee, 0xaa, 0x0, 0xad, 0x14, 0x59, 0xd2, 0x36, 0x5a, 0x58, 0xee, 0xaa, 0xbd, 0xd4, 0x35, 0xd9, 0xa2, 0x17, 0x99, 0x31, 0x9f, 0xcc, 0x86, 0x68, 0xb4, 0xbe, 0xa1, 0xb5, 0x5f, 0x34, 0x15, 0x6c, 0x82, 0xcc, 0x2e, 0xcc, 0x7b, 0x3f, 0x5b, 0x20, 0xc, 0xd8, 0x7b, 0xe, 0xac, 0x4b, 0x5b, 0x8, 0x6c, 0x9b, 0x35, 0xc, 0xbe, 0xab, 0x77, 0x75, 0x1d, 0x9d, 0x5b, 0x24, 0xbf, 0x21, 0xdd, 0x19, 0x8a, 0xd, 0x83, 0xec, 0xf1, 0xa0, 0x27, 0xf, 0xb3, 0xb1, 0x1c, 0x79, 0xbb, 0x58, 0xc7, 0xf9, 0x1e, 0x3c, 0x8, 0x81, 0x70, 0x3a, 0x9a, 0x28, 0x22, 0x37, 0x6, 0x8a, 0x6b, 0xa8, 0xfc, 0x7, 0x5f, 0x63, 0x84, 0x54, 0x9, 0x93, 0x8, 0x41, 0xfc, 0xf6, 0x36, 0x6, 0x8, 0x8a, 0x9, 0x82, 0xe2, 0x26, 0x4, 0xf1, 0x7f, 0x33, 0x4, 0xc5, 0x26, 0x90, 0xe4, 0x36, 0xab, 0x6c, 0xec, 0x54, 0xde, 0x64, 0xb1, 0xfb, 0x1f, 0xff, 0xb, 0xe1, 0xe6, 0xce, 0x71, 0xa9, 0x9c, 0xde, 0x83, 0xee, 0x51, 0x61, 0x6, 0xd9, 0x9f, 0x20, 0x56, 0x40, 0x3b, 0xa, 0xb2, 0xab, 0x2d, 0x59, 0x31, 0xb1, 0x9b, 0x18, 0x49, 0x26, 0x4f, 0x27, 0xfc, 0x19, 0x6b, 0xac, 0x71, 0xb7, 0xb9, 0xdf, 0x1f, 0x1d, 0x76, 0x72, 0x34, 0x4d, 0x84, 0x67, 0x22, 0xa4, 0x62, 0xa2, 0x14, 0xc6, 0x5d, 0x3a, 0x5b, 0x28, 0x21, 0xb1, 0x53, 0xe8, 0xe1, 0x8b, 0xc3, 0xb6, 0x76, 0x62, 0xc8, 0x86, 0x34, 0xa, 0x61, 0x9, 0xa3, 0xf, 0x87, 0xba, 0xb6, 0xc4, 0x38, 0x76, 0xcb, 0xf7, 0x90, 0xaf, 0xd1, 0x93, 0x26, 0xba, 0xf0, 0xcf, 0x5a, 0xb2, 0x14, 0xe1, 0x86, 0xf3, 0x80, 0x35, 0x69, 0xbb, 0x43, 0x44, 0x2b, 0x89, 0x97, 0xea, 0x37, 0x35, 0xa8, 0x3d, 0x79, 0x79, 0x96, 0xbc, 0x4e, 0xd7, 0xc5, 0x4a, 0x12, 0x91, 0x1f, 0xe4, 0xb, 0xd9, 0xa2, 0x8e, 0x41, 0xee, 0x1f, 0xd3, 0xa2, 0x48, 0xfb, 0xdc, 0xbb, 0x59, 0xc, 0xc5, 0x60, 0xc4, 0x57, 0x35, 0xf3, 0xa0, 0xa3, 0xc, 0xd4, 0x49, 0x87, 0x59, 0x9b, 0xa4, 0xca, 0x99, 0xe3, 0x9a, 0x3f, 0x5c, 0x27, 0x93, 0x7f, 0xea, 0x4, 0xe5, 0x37, 0xaf, 0x68, 0x6b, 0x9e, 0x1b, 0x4e, 0x57, 0xb6, 0x40, 0xf6, 0x3f, 0x51, 0xc3, 0x41, 0x3a, 0x5a, 0xc, 0xc6, 0xb2, 0xb9, 0x98, 0xf1, 0x35, 0xb7, 0x2, 0x13, 0x68, 0xb6, 0x52, 0x9b, 0xb2, 0x1c, 0x35, 0x59, 0xab, 0x2d, 0x33, 0x97, 0x25, 0x74, 0x9a, 0xec, 0x97, 0xc2, 0x68, 0x9f, 0x2d, 0xd8, 0x92, 0xad, 0x59, 0xc2, 0x36, 0x2c, 0x6d, 0x0, 0x2b, 0x6c, 0x8b, 0xe0, 0x7b, 0xf1, 0xa0, 0xd2, 0x1c, 0x3f, 0xd3, 0xa, 0x2, 0x66, 0xde, 0xec, 0xe2, 0xb3, 0xce, 0xc6, 0x5, 0x3d, 0x9b, 0xc3, 0x5a, 0xd5, 0x42, 0xbd, 0x12, 0x59, 0xe5, 0x45, 0x44, 0xbb, 0x35, 0xe6, 0x4a, 0xaf, 0xaf, 0x24, 0xec, 0xc, 0x75, 0x2f, 0x21, 0xf6, 0xa3, 0x39, 0x71, 0xb1, 0x29, 0x91, 0x52, 0xaf, 0x11, 0x8a, 0xd1, 0xc6, 0xbd, 0x19, 0xbe, 0xea, 0xd4, 0x21, 0x26, 0xef, 0xdc, 0x36, 0x43, 0xff, 0x79, 0x96, 0x9d, 0xc3, 0xf6, 0xc8, 0x8b, 0xdd, 0x7, 0xc, 0x5, 0xbd, 0xec, 0xf6, 0x36, 0x53, 0xf2, 0x9e, 0x31, 0x94, 0xa3, 0x63, 0xc, 0x7c, 0x42, 0x82, 0xd0, 0xe0, 0xaa, 0x57, 0x9e, 0xae, 0x80, 0x16, 0xc0, 0x2a, 0xe1, 0x37, 0x50, 0x4b, 0xba, 0xcc, 0xbb, 0xea, 0x97, 0x27, 0x73, 0x48, 0x9e, 0x47, 0xf4, 0xd, 0x94, 0x2e, 0xb, 0x82, 0xb0, 0x3d, 0x2b, 0x54, 0xf4, 0xe3, 0xcd, 0xaf, 0xd1, 0x6, 0xa7, 0x36, 0x42, 0xa9, 0xeb, 0xb0, 0xca, 0x22, 0x11, 0xbc, 0xea, 0x73, 0xa3, 0x65, 0x4e, 0x2d, 0x8f, 0x97, 0xd1, 0x9c, 0xad, 0x8d, 0x90, 0x84, 0x2b, 0xe3, 0xda, 0x5e, 0x93, 0x5f, 0x58, 0xb5, 0x2f, 0x30, 0xe2, 0x30, 0x19, 0x96, 0xf8, 0x39, 0x46, 0x47, 0x74, 0xa4, 0xc7, 0x18, 0x22, 0x76, 0x7d, 0xa4, 0x5, 0xb2, 0xa2, 0x57, 0x7, 0x80, 0x62, 0x9b, 0x68, 0x59, 0xe7, 0x2c, 0xcc, 0x9c, 0x24, 0x9a, 0xf9, 0x49, 0x30, 0x49, 0xc2, 0x21, 0x14, 0x9a, 0xf9, 0x9b, 0x60, 0xb2, 0x51, 0x6a, 0x2a, 0x13, 0x4b, 0xa4, 0x7d, 0x7f, 0xd3, 0x4b, 0x2, 0x25, 0x43, 0x2, 0x2c, 0xb, 0xc, 0x26, 0x2c, 0x9e, 0x36, 0xf8, 0xc2, 0x6, 0xb3, 0x13, 0xbb, 0xcd, 0xd5, 0x84, 0xe8, 0x22, 0xd, 0xce, 0x8c, 0x4e, 0x50, 0x3, 0xd2, 0x6b, 0x26, 0x4a, 0x41, 0x54, 0x34, 0x1c, 0x81, 0x1c, 0xc1, 0xf5, 0x20, 0xae, 0x65, 0xa2, 0x75, 0x3e, 0xe8, 0x98, 0xd6, 0xcb, 0xe2, 0xc0, 0xad, 0xdd, 0x67, 0x54, 0xcb, 0x30, 0x87, 0x59, 0x5f, 0x2f, 0x11, 0x35, 0x68, 0x41, 0x6d, 0xf7, 0xcc, 0xec, 0x1d, 0xa9, 0x82, 0xda, 0xe2, 0x49, 0xeb, 0x7, 0xb8, 0xb6, 0x43, 0x94, 0x73, 0x52, 0xd6, 0xeb, 0xb8, 0x33, 0x75, 0xa6, 0x9c, 0xdb, 0xf6, 0xdd, 0xad, 0xef, 0x30, 0x18, 0x64, 0x87, 0xe4, 0xa1, 0xe2, 0xd3, 0x2, 0xf, 0x26, 0x39, 0x49, 0xb4, 0x4d, 0x3b, 0xf4, 0x5b, 0xd4, 0xa6, 0x46, 0xa9, 0x1a, 0x8, 0xe5, 0x80, 0xa4, 0x8d, 0x81, 0xc5, 0xe2, 0x48, 0x67, 0xaa, 0xdd, 0x7c, 0x4e, 0x37, 0x7f, 0x64, 0x50, 0xa7, 0xa0, 0xdb, 0x74, 0x50, 0x2e, 0x96, 0x39, 0x16, 0xc0, 0x96, 0xf7, 0x30, 0x1e, 0xf4, 0xe5, 0xf5, 0x93, 0xd5, 0xb4, 0xa1, 0x60, 0x1a, 0x8e, 0xe3, 0x36, 0xce, 0x8a, 0x1, 0x67, 0x95, 0x1d, 0x38, 0x2b, 0x6e, 0xa8, 0x1e, 0x4d, 0x52, 0x5e, 0x53, 0x13, 0xde, 0xa4, 0x26, 0x1, 0x61, 0xa6, 0x78, 0xa2, 0x99, 0x3c, 0xbc, 0x1, 0x43, 0x2b, 0xa8, 0xb0, 0xb6, 0x1b, 0x92, 0x29, 0xe3, 0xae, 0x99, 0x6c, 0xd5, 0xda, 0xd7, 0xa2, 0x9c, 0x0, 0x88, 0x5f, 0x71, 0x2d, 0xad, 0x9b, 0x7a, 0x24, 0x29, 0xbb, 0x7a, 0x23, 0xa9, 0xc3, 0x5, 0xbe, 0x25, 0x2, 0x2b, 0x8e, 0xc0, 0xbc, 0x63, 0x32, 0xae, 0x59, 0x24, 0xdc, 0x2c, 0x14, 0xe9, 0x6a, 0x30, 0x10, 0xdf, 0xb3, 0xa2, 0x79, 0xc5, 0xe2, 0x2c, 0xf7, 0x3, 0xd3, 0x56, 0x3b, 0xad, 0x16, 0x9c, 0xb6, 0x3b, 0x2d, 0x46, 0x65, 0xfb, 0x1e, 0x96, 0x4, 0xe6, 0x6d, 0x62, 0xed, 0x38, 0xd4, 0xbe, 0x46, 0x93, 0x0, 0x59, 0x50, 0x70, 0x5d, 0x21, 0xc6, 0xed, 0x5b, 0x80, 0x7d, 0xd3, 0x3a, 0x1, 0x64, 0x76, 0xb7, 0x53, 0xe6, 0xd1, 0x25, 0xa8, 0x5b, 0xd, 0xb2, 0x59, 0x8b, 0xae, 0xf5, 0x47, 0xe3, 0xc, 0x43, 0xaa, 0x67, 0x18, 0x52, 0x5d, 0x3b, 0x51, 0x5a, 0xed, 0xab, 0x13, 0xcf, 0x3b, 0x9, 0xf1, 0x9d, 0x40, 0x1d, 0x5f, 0xe1, 0x35, 0xcf, 0x2e, 0xb3, 0x18, 0xc7, 0x19, 0x35, 0x85, 0x5f, 0x80, 0x6e, 0x8e, 0x56, 0x7f, 0x9d, 0x2, 0xb0, 0x21, 0xdc, 0xbe, 0xe7, 0x0, 0x41, 0x1e, 0x6a, 0x98, 0x9d, 0xfd, 0x46, 0xbc, 0x4d, 0xb, 0x1c, 0xec, 0x62, 0x62, 0x87, 0xc, 0xcb, 0x2c, 0xcb, 0xe0, 0x42, 0xc9, 0xcb, 0x56, 0x22, 0x50, 0xb1, 0x45, 0x14, 0xc3, 0xbf, 0xcb, 0x68, 0x71, 0x8a, 0xc, 0xcb, 0x69, 0xd1, 0x47, 0xff, 0x52, 0x64, 0x5c, 0x16, 0x82, 0x7f, 0x81, 0x4, 0x4b, 0xcb, 0x43, 0xac, 0xcd, 0x44, 0x81, 0x6e, 0x98, 0x11, 0x3e, 0xd1, 0x3f, 0xe3, 0x53, 0xc8, 0x13, 0x66, 0x3e, 0x1d, 0xea, 0xa0, 0x75, 0x2d, 0x72, 0x2d, 0x27, 0xde, 0xb4, 0xa8, 0xaa, 0xe2, 0xc2, 0x21, 0x7d, 0xd9, 0xbc, 0x15, 0x53, 0x58, 0x9, 0x1f, 0x7e, 0x23, 0xbf, 0x4e, 0x15, 0x74, 0x47, 0x86, 0x6, 0x61, 0x9e, 0x88, 0x50, 0xe0, 0xb1, 0x26, 0x53, 0xeb, 0x8, 0x41, 0x6f, 0x7, 0x69, 0x42, 0xb5, 0xb8, 0xfb, 0x2d, 0x56, 0xa0, 0x85, 0xb5, 0x8b, 0xb4, 0xed, 0xef, 0xa0, 0x9d, 0x85, 0xac, 0x38, 0xf, 0x2a, 0xc8, 0x3, 0x7e, 0xa0, 0xa3, 0x3f, 0x1a, 0xe0, 0xa2, 0x1b, 0xe7, 0x3, 0x11, 0x2, 0xa, 0xd8, 0xe1, 0x89, 0xf0, 0xa0, 0xf6, 0xdb, 0x5c, 0x3b, 0xdf, 0x6, 0x21, 0xc6, 0x1a, 0x6, 0xa4, 0x55, 0xbb, 0x57, 0x5f, 0x14, 0xe9, 0x6, 0x2d, 0xb4, 0xc5, 0x5f, 0x7c, 0x17, 0xad, 0x58, 0x93, 0x87, 0xb5, 0x9d, 0x10, 0xd1, 0x5, 0x34, 0xbd, 0x69, 0x15, 0x61, 0xc4, 0xff, 0xbc, 0x78, 0x5c, 0xe4, 0xb3, 0x65, 0x96, 0xb8, 0x5e, 0x79, 0x55, 0x5, 0x81, 0x10, 0xc3, 0x52, 0x1a, 0x3e, 0xf8, 0xec, 0x1d, 0xdf, 0xce, 0xca, 0xd4, 0x73, 0x27, 0xc0, 0x33, 0xdd, 0xb4, 0xdf, 0x27, 0x1a, 0xd6, 0x6f, 0x1e, 0x69, 0x2d, 0x8f, 0x4e, 0xfd, 0x8b, 0xa9, 0x4a, 0xb1, 0x9f, 0x4f, 0x1a, 0x3e, 0x50, 0xef, 0x27, 0xfd, 0xc5, 0x54, 0xc8, 0x98, 0x6f, 0x28, 0x35, 0xb4, 0x90, 0x56, 0x5f, 0x96, 0x2e, 0x8, 0x73, 0xa6, 0xf1, 0xfa, 0xb9, 0x36, 0x78, 0x55, 0x9, 0xb5, 0x8d, 0x6d, 0x78, 0x8c, 0x9, 0x44, 0x1e, 0x9f, 0xaf, 0xe2, 0x4, 0x3d, 0xf1, 0x1e, 0x60, 0xca, 0xa7, 0xc2, 0x29, 0x59, 0xa5, 0x8d, 0x98, 0x1d, 0x6a, 0x20, 0xfc, 0xe8, 0x64, 0xb3, 0xdc, 0x4b, 0x96, 0x71, 0x59, 0x46, 0xf8, 0xf8, 0x4c, 0xde, 0x7a, 0xc2, 0xf3, 0xc3, 0xd3, 0xbe, 0xa8, 0xe2, 0x9d, 0x9e, 0x7c, 0x48, 0x9e, 0x40, 0x12, 0x73, 0xe, 0xc7, 0x7b, 0xd9, 0x49, 0xc3, 0x79, 0x1b, 0x92, 0xf0, 0xd1, 0x8b, 0xf, 0x4f, 0x4f, 0x96, 0xd9, 0xe9, 0x49, 0xb9, 0x8a, 0xf3, 0x3d, 0x72, 0xe3, 0x8f, 0xbc, 0xa9, 0x36, 0x64, 0xe8, 0x27, 0xb4, 0x58, 0xd0, 0x99, 0xf6, 0xd4, 0xce, 0xce, 0x6b, 0x3, 0x93, 0xf, 0x4f, 0xa1, 0xa3, 0x23, 0xac, 0x7a, 0x8a, 0xf, 0xea, 0xf8, 0x66, 0x21, 0xf3, 0x6d, 0x9d, 0x56, 0x3a, 0xa6, 0xe2, 0x2b, 0x3b, 0x47, 0xd8, 0xb5, 0xf8, 0xda, 0x2c, 0x4f, 0x3f, 0xda, 0x8e, 0x33, 0xd3, 0xdf, 0x4b, 0x3e, 0x8e, 0xea, 0x3d, 0x8a, 0x81, 0x60, 0x29, 0xe7, 0xa8, 0x10, 0x20, 0xc2, 0xa1, 0xe8, 0xa8, 0x2c, 0x1d, 0xa1, 0x3c, 0x2a, 0x82, 0x89, 0x26, 0xe9, 0xf3, 0x31, 0x2d, 0x5b, 0x26, 0x7e, 0xe8, 0xf6, 0x1b, 0x1a, 0x41, 0x7a, 0x28, 0x4a, 0x61, 0x5a, 0xe8, 0xf5, 0xfb, 0xd0, 0xf5, 0x92, 0x4e, 0x53, 0xc1, 0x88, 0x78, 0x86, 0xf6, 0xd5, 0xd7, 0x5c, 0xa3, 0xa5, 0xa3, 0xec, 0xe7, 0xb5, 0xb1, 0xaa, 0xd9, 0xba, 0xa8, 0xa3, 0xb9, 0xe5, 0xbd, 0xa2, 0x17, 0x3, 0x1b, 0x9c, 0x1d, 0x22, 0xd, 0x6f, 0xc0, 0x42, 0x2f, 0xb6, 0xb4, 0x28, 0xba, 0xc7, 0x4e, 0xef, 0xbf, 0x3b, 0x6e, 0xb, 0xfb, 0xc7, 0xa2, 0x17, 0x13, 0x6, 0xad, 0xf6, 0xd7, 0x8d, 0xe6, 0x1b, 0xde, 0x7, 0x8e, 0xa9, 0xf7, 0x29, 0xb6, 0xac, 0x6b, 0xf0, 0xda, 0xc7, 0xec, 0xa8, 0x42, 0x44, 0x6a, 0xf9, 0xdf, 0xa3, 0x8f, 0xbe, 0xe5, 0x9, 0x69, 0xbe, 0xdb, 0x85, 0xfe, 0x1e, 0x75, 0xf0, 0x2d, 0xc3, 0xa3, 0xab, 0xe1, 0x6e, 0x29, 0xf2, 0x1d, 0x5e, 0xb5, 0xf5, 0x73, 0x5d, 0x18, 0xa5, 0x81, 0x7c, 0xf4, 0x26, 0x8a, 0xcc, 0xc2, 0x1c, 0xcb, 0x87, 0x95, 0x40, 0xe8, 0x55, 0x10, 0x9e, 0x9d, 0x8f, 0xf5, 0xf3, 0x86, 0x98, 0xe5, 0xdb, 0xb8, 0x57, 0x29, 0xe4, 0xce, 0x3c, 0xd, 0xfc, 0x1e, 0xf3, 0xc, 0xa3, 0x7a, 0x8f, 0x9c, 0xff, 0xb9, 0xb0, 0x52, 0xca, 0x1a, 0x98, 0x5b, 0xd7, 0x81, 0x41, 0x2c, 0x80, 0x44, 0x2d, 0x91, 0x4c, 0x7d, 0x26, 0xac, 0x73, 0x8c, 0x36, 0xcc, 0x5c, 0x81, 0x2e, 0xb6, 0x6, 0xb3, 0xaa, 0x1c, 0x81, 0x29, 0x3e, 0x39, 0xa5, 0xc2, 0x38, 0x15, 0x58, 0x6b, 0x87, 0x6, 0xd, 0xda, 0x86, 0x4d, 0xbf, 0xed, 0x6b, 0x6a, 0xe3, 0x22, 0x56, 0x5b, 0xe6, 0xb7, 0x8b, 0xe9, 0x2c, 0x87, 0xe7, 0x73, 0x3d, 0xdb, 0xca, 0x1d, 0x4d, 0x41, 0xc6, 0x56, 0xa7, 0xf3, 0x1e, 0x66, 0xe2, 0xdc, 0xcb, 0x27, 0xd9, 0x6b, 0xd7, 0xe2, 0xac, 0x15, 0xa7, 0x40, 0xa5, 0x9b, 0xe, 0xb, 0x18, 0x8a, 0x1, 0x76, 0x68, 0x3b, 0xb6, 0x83, 0x50, 0x88, 0xd8, 0x9, 0xf5, 0xaa, 0x8b, 0xb7, 0x3d, 0x8d, 0xf7, 0x97, 0x72, 0xbc, 0x56, 0xc3, 0xca, 0xa2, 0x28, 0x7a, 0x51, 0x5a, 0xb, 0xe7, 0xab, 0xb0, 0xeb, 0xc2, 0xa1, 0x1c, 0x25, 0x12, 0x41, 0xfe, 0xf3, 0x73, 0x26, 0x7b, 0xf9, 0xd2, 0x1c, 0xfe, 0x8e, 0x21, 0xba, 0xa7, 0x64, 0x6d, 0x36, 0xe4, 0x58, 0xbf, 0xd1, 0x4f, 0xd5, 0x51, 0x54, 0x6e, 0x46, 0xd6, 0x84, 0x5, 0x8a, 0x45, 0x61, 0xc6, 0x6a, 0xd0, 0x66, 0x57, 0x86, 0x3f, 0x9f, 0x50, 0x38, 0xca, 0x57, 0xe, 0x95, 0x39, 0xa9, 0xd, 0x2d, 0x86, 0x7b, 0x2b, 0xba, 0x3c, 0x48, 0x3d, 0xa2, 0x40, 0x8b, 0x52, 0x15, 0xce, 0xba, 0x8e, 0x82, 0x8, 0x56, 0xa5, 0x81, 0xac, 0x62, 0x37, 0x86, 0x71, 0xa7, 0x68, 0xc3, 0x81, 0xe1, 0x1c, 0x91, 0x43, 0x2, 0x76, 0xd5, 0x55, 0xe9, 0x7b, 0x67, 0x5, 0x6, 0x68, 0x3f, 0x50, 0xbe, 0x52, 0xf6, 0x68, 0xb7, 0xb5, 0xca, 0xdf, 0x5a, 0xa, 0xc1, 0x10, 0xf9, 0x41, 0xa7, 0x6e, 0x58, 0x34, 0x23, 0x32, 0xfd, 0x1a, 0x9c, 0xdb, 0xa1, 0x58, 0xd8, 0x7b, 0x21, 0x83, 0x5d, 0xf8, 0x44, 0xe, 0xb7, 0x35, 0x52, 0x55, 0xdc, 0xc2, 0xbc, 0x7c, 0x77, 0xe0, 0x12, 0xb9, 0x25, 0xe2, 0x8, 0x20, 0xb4, 0x33, 0xb1, 0x81, 0xac, 0xac, 0x21, 0xc4, 0x46, 0x78, 0x56, 0xeb, 0x5a, 0xbe, 0x62, 0x84, 0x8d, 0xd1, 0x6b, 0xcf, 0x11, 0x87, 0x13, 0x99, 0x56, 0x3b, 0x8e, 0x8e, 0xb2, 0x41, 0xa3, 0x2e, 0x29, 0x5e, 0x22, 0x33, 0xb4, 0xa, 0x4d, 0x66, 0x3, 0x35, 0xb, 0xd8, 0x93, 0xa1, 0x2c, 0xd5, 0x5c, 0x41, 0x2c, 0x62, 0xc2, 0xa8, 0xa2, 0x99, 0x7c, 0x44, 0xcc, 0x55, 0x6, 0x39, 0x8, 0xe9, 0x8, 0xe4, 0xe7, 0xc0, 0xa0, 0xe7, 0xc0, 0xa0, 0xeb, 0xf7, 0x84, 0x5c, 0xcb, 0x54, 0x0, 0xe7, 0xae, 0x3, 0xc0, 0x48, 0xfd, 0xbb, 0x78, 0x9c, 0xf3, 0x3e, 0x6e, 0xed, 0x82, 0xd, 0xad, 0x43, 0xc8, 0x64, 0x8e, 0xfd, 0xa4, 0xa8, 0x93, 0xb4, 0x14, 0x99, 0x72, 0x7a, 0xa5, 0x47, 0xdd, 0xf2, 0xe8, 0xc6, 0xd6, 0xe1, 0xda, 0xf8, 0xb5, 0x7e, 0x8a, 0x53, 0x39, 0x41, 0xb5, 0x83, 0x3a, 0x19, 0x87, 0xcb, 0xc, 0x3, 0xe5, 0x8, 0x43, 0xd1, 0x11, 0x84, 0xc1, 0x7e, 0x40, 0xb3, 0x23, 0x60, 0x82, 0xf5, 0x1c, 0x67, 0x57, 0xf0, 0x5, 0xfb, 0x89, 0xce, 0xce, 0x60, 0xe, 0x8d, 0xf7, 0x41, 0x99, 0x21, 0xad, 0x87, 0x2a, 0x8, 0x11, 0x9b, 0x1a, 0x3c, 0x7b, 0xbb, 0xb6, 0xc1, 0xd1, 0x3, 0xa7, 0x67, 0x3c, 0x49, 0xda, 0x2e, 0x6a, 0xbe, 0x58, 0xda, 0x32, 0x85, 0x69, 0xef, 0x2f, 0x77, 0xbd, 0xd3, 0xe3, 0x93, 0xa1, 0x9c, 0xcb, 0xbc, 0xd5, 0x18, 0xa6, 0xf2, 0x82, 0xac, 0xbb, 0xb, 0xc6, 0xdc, 0x32, 0xd8, 0xc0, 0x90, 0xdb, 0xf2, 0xea, 0x3a, 0xac, 0x68, 0x79, 0x42, 0x6e, 0x84, 0x73, 0xf4, 0x77, 0xac, 0xf8, 0xae, 0x75, 0xde, 0xb5, 0xb8, 0x1, 0xd3, 0xaa, 0x15, 0x17, 0x68, 0x69, 0x15, 0x8b, 0x56, 0x47, 0x76, 0x94, 0x92, 0xd4, 0xd7, 0x21, 0xe4, 0xb4, 0xcb, 0x3b, 0x44, 0x21, 0xd6, 0xba, 0xe, 0xef, 0xa8, 0x67, 0x95, 0x61, 0xd6, 0xd5, 0x77, 0x47, 0x8d, 0xfa, 0xaa, 0xbe, 0x9d, 0x6f, 0x4b, 0x6a, 0x43, 0x66, 0xdd, 0x94, 0xff, 0x8a, 0xf6, 0x1c, 0x6f, 0xb9, 0x82, 0x70, 0xb8, 0x72, 0x45, 0x4c, 0xd1, 0xf, 0xfd, 0x4e, 0x86, 0x3b, 0x78, 0xa7, 0xc9, 0xe, 0xee, 0x2b, 0x14, 0xf, 0xd5, 0x2a, 0xb8, 0x71, 0xe, 0x5a, 0x6a, 0xb3, 0x95, 0x63, 0xbc, 0x7b, 0x4, 0x92, 0x35, 0xb2, 0x2a, 0xab, 0x57, 0x87, 0x91, 0x8d, 0x96, 0xa0, 0x9a, 0xb3, 0x9b, 0xe6, 0x31, 0xe1, 0xf4, 0xba, 0x1e, 0x13, 0x4f, 0x1c, 0x39, 0x46, 0x40, 0x36, 0x43, 0xf5, 0xc3, 0x47, 0xee, 0x12, 0x2, 0xd0, 0xf0, 0x49, 0x24, 0x57, 0xbe, 0x7a, 0xc7, 0x98, 0x5e, 0x4b, 0xda, 0x55, 0xa0, 0xd7, 0xd1, 0xff, 0xe1, 0x8e, 0x5e, 0x35, 0x8b, 0x4c, 0xb7, 0xe2, 0x9a, 0xc5, 0xab, 0x85, 0x3e, 0x1f, 0xed, 0xcd, 0x60, 0xfb, 0x50, 0x28, 0x69, 0x5c, 0x61, 0xf0, 0xf6, 0x13, 0x93, 0x2a, 0x96, 0x42, 0x4d, 0x79, 0xf8, 0xf9, 0x7d, 0x58, 0xc8, 0x4a, 0xb2, 0x90, 0xd9, 0x3b, 0x33, 0x36, 0xdc, 0x18, 0xbf, 0x65, 0xc9, 0x3d, 0xea, 0xe0, 0x77, 0xd8, 0x7b, 0xf3, 0x5c, 0xc8, 0xef, 0x39, 0x5b, 0x34, 0xf9, 0xda, 0xd6, 0xec, 0xdd, 0x6c, 0x6e, 0xab, 0x98, 0xce, 0x2, 0xce, 0xf4, 0xf, 0x16, 0x23, 0x26, 0x3a, 0xd3, 0x46, 0xed, 0xda, 0x5a, 0x59, 0x71, 0x5e, 0xca, 0x4c, 0xdd, 0xde, 0x21, 0x8b, 0x49, 0x33, 0xed, 0xd8, 0x1b, 0xac, 0x5a, 0x9b, 0x23, 0x22, 0xe, 0x8b, 0xf6, 0x4c, 0x5a, 0xb6, 0x5b, 0xa3, 0x31, 0x7b, 0xa5, 0x18, 0x99, 0x56, 0x9c, 0x68, 0x3, 0xa7, 0x3b, 0x38, 0x66, 0x76, 0xe3, 0xde, 0x91, 0xae, 0x85, 0xdd, 0x2a, 0x6f, 0x9d, 0x5a, 0x2e, 0x7b, 0x47, 0x62, 0xbf, 0x95, 0xb6, 0x78, 0x16, 0xaf, 0x5a, 0x5, 0xdd, 0xd1, 0x1, 0x6e, 0x6f, 0x47, 0x63, 0x33, 0xf2, 0xe4, 0xb8, 0xe9, 0x9d, 0x5c, 0xb7, 0x46, 0x41, 0x86, 0xb2, 0x3b, 0x57, 0xd3, 0xe0, 0x2f, 0xc5, 0xb2, 0x36, 0x8f, 0x8b, 0x15, 0xe, 0x8f, 0xca, 0x74, 0x89, 0x15, 0x83, 0x3a, 0xb0, 0x89, 0x7f, 0xf3, 0xee, 0x12, 0x0, 0x6f, 0x9c, 0x88, 0x1a, 0x97, 0x41, 0xaf, 0x82, 0xf7, 0x7a, 0xef, 0xc3, 0xb1, 0x5, 0x84, 0x20, 0xc3, 0x2e, 0x35, 0x4, 0xab, 0xed, 0xd6, 0x8c, 0xdc, 0xf8, 0x2b, 0x75, 0x96, 0x22, 0x98, 0xa0, 0xad, 0x1d, 0x54, 0x89, 0xc6, 0x21, 0x94, 0x6f, 0x46, 0x5b, 0x39, 0x4a, 0x77, 0x8, 0x6d, 0xa1, 0xee, 0x3b, 0x9e, 0x3, 0xff, 0x93, 0xf3, 0xf5, 0xe3, 0x4d, 0x55, 0x6c, 0xaa, 0xf0, 0x41, 0xeb, 0xa5, 0xfa, 0xd1, 0xb0, 0xfb, 0xa9, 0x7a, 0xf1, 0x42, 0x84, 0x27, 0xf3, 0x39, 0x99, 0x37, 0xf1, 0xfa, 0xb5, 0x7b, 0x2e, 0xdf, 0xaf, 0xff, 0xad, 0x55, 0x90, 0x2a, 0x96, 0xe2, 0x7b, 0xa9, 0x20, 0x55, 0xe5, 0x9d, 0x2a, 0x48, 0xb3, 0x90, 0xa9, 0x82, 0x6c, 0xa5, 0xbf, 0x9b, 0xa, 0xf2, 0xd3, 0x62, 0x33, 0x5f, 0xe4, 0x9b, 0xea, 0x3e, 0x7a, 0x48, 0x69, 0x29, 0x30, 0x57, 0x41, 0x48, 0x5b, 0x61, 0x38, 0x22, 0x9f, 0xe3, 0x5d, 0xa9, 0xb4, 0x70, 0xb1, 0x2, 0xbc, 0x36, 0xb1, 0xc2, 0xb9, 0xd4, 0xde, 0x69, 0xda, 0xd7, 0x2, 0x88, 0xa3, 0x63, 0x6d, 0x18, 0xf0, 0x5c, 0x64, 0x62, 0x34, 0x97, 0xc, 0x63, 0xba, 0xe8, 0x39, 0x38, 0x4, 0x86, 0xab, 0xb0, 0xed, 0xc3, 0xa9, 0xe, 0x97, 0x39, 0x80, 0xa3, 0xe3, 0x6d, 0xf0, 0x6f, 0xd2, 0xd0, 0xc9, 0xe9, 0x34, 0xb4, 0x74, 0x26, 0xb2, 0xd2, 0xa1, 0x39, 0xef, 0x96, 0xcf, 0xdf, 0x59, 0x3d, 0x27, 0x49, 0xd9, 0x2e, 0xfd, 0x9b, 0xc6, 0x2c, 0x2f, 0xe0, 0xf8, 0x2c, 0xfd, 0xaa, 0xc6, 0xa4, 0xae, 0xe0, 0x4f, 0x92, 0x5, 0x21, 0x25, 0x8a, 0x11, 0x16, 0xb6, 0xa1, 0x0, 0x68, 0xcf, 0xdb, 0x81, 0xe4, 0x1, 0xa6, 0xca, 0x4e, 0x31, 0x7d, 0xec, 0x10, 0x87, 0x3b, 0x16, 0x4a, 0x49, 0xd2, 0xea, 0xaa, 0xb, 0x3, 0xa5, 0xa8, 0x97, 0xb5, 0x55, 0xd4, 0x5a, 0x37, 0xef, 0x54, 0xdb, 0xe4, 0x66, 0xd2, 0x95, 0xa4, 0x79, 0xb4, 0xed, 0x44, 0x7c, 0xd9, 0x31, 0x41, 0x2b, 0xcc, 0x21, 0xab, 0x59, 0x34, 0xd, 0xae, 0x9a, 0x89, 0x12, 0x48, 0x9c, 0x19, 0x67, 0x25, 0x74, 0xc4, 0x90, 0xe6, 0x36, 0xd3, 0x6d, 0xc4, 0xb7, 0x31, 0xe2, 0xd4, 0xbc, 0x53, 0xc5, 0x23, 0xc0, 0x95, 0x36, 0x93, 0xe9, 0x44, 0xb2, 0x26, 0xfb, 0x33, 0x48, 0x6c, 0xb5, 0x9d, 0x4a, 0xd6, 0x9, 0x18, 0x5b, 0x35, 0xd1, 0xa2, 0x95, 0x4b, 0xc5, 0xda, 0x22, 0x6, 0xac, 0x53, 0x69, 0xdb, 0x3e, 0xf7, 0x6d, 0x9e, 0xcd, 0x59, 0x56, 0xa9, 0x56, 0x55, 0x80, 0x9e, 0x70, 0xa4, 0x1e, 0x85, 0x7b, 0xfa, 0x5, 0x4b, 0x2c, 0xb3, 0x3e, 0xd7, 0x82, 0x9, 0xc2, 0xa0, 0x56, 0xac, 0xbe, 0x85, 0x36, 0x2b, 0xd6, 0xb4, 0xd7, 0xd2, 0xa2, 0x6e, 0xd1, 0xeb, 0x2, 0xdf, 0xeb, 0x68, 0xc7, 0x18, 0x57, 0x2c, 0x98, 0xe9, 0x8, 0xd2, 0x61, 0x62, 0x58, 0xb5, 0x6d, 0xc, 0xe5, 0xe3, 0x6e, 0xf8, 0xa4, 0x97, 0xf2, 0x6c, 0xa8, 0xf0, 0x0, 0x9a, 0xad, 0xd1, 0x89, 0x6c, 0x63, 0x65, 0x2a, 0x17, 0xd, 0x5d, 0xe7, 0xd4, 0x2c, 0xd1, 0xab, 0x1f, 0xd1, 0x55, 0x73, 0xd3, 0x2c, 0x41, 0x87, 0x2e, 0xb1, 0x89, 0xb, 0x4c, 0xe8, 0xff, 0x95, 0xaa, 0x45, 0x13, 0x75, 0xed, 0x3a, 0xcd, 0x5d, 0x3a, 0x45, 0x17, 0x73, 0x6d, 0xe8, 0x44, 0xd4, 0xb3, 0xe3, 0xf4, 0xa4, 0x76, 0xe8, 0x3a, 0xcb, 0xfd, 0x91, 0xfb, 0x34, 0x67, 0xe8, 0x1c, 0xb3, 0x63, 0x7b, 0xef, 0xe6, 0xb0, 0x6b, 0x14, 0x60, 0xf2, 0xd8, 0xef, 0x41, 0x9b, 0xfe, 0xa9, 0xc4, 0xf5, 0x1e, 0x6b, 0x2f, 0xa7, 0x7c, 0xd3, 0xc6, 0x5c, 0x3b, 0xb1, 0xd3, 0x3b, 0x63, 0xa0, 0x6d, 0xd, 0x88, 0x5d, 0x2, 0x0, 0x6c, 0xa2, 0x2d, 0x1, 0xdc, 0x35, 0x7e, 0xc1, 0xc3, 0x9b, 0x9c, 0xb9, 0x3, 0x2f, 0xdc, 0x75, 0xf4, 0xff, 0xe9, 0x13, 0x67, 0x64, 0xa7, 0xaa, 0xe2, 0x8e, 0x45, 0x95, 0x19, 0xbb, 0xd, 0x10, 0xad, 0x39, 0x2a, 0xc, 0xcd, 0x29, 0x82, 0xa6, 0xa3, 0xe5, 0x8, 0x27, 0x99, 0xa4, 0x2e, 0x1d, 0x19, 0x18, 0x10, 0xd6, 0xe6, 0xc4, 0xd, 0xf1, 0xca, 0xe5, 0x4f, 0xf3, 0x8d, 0xbc, 0x37, 0x3a, 0x37, 0x5b, 0xa9, 0xc7, 0x62, 0xc8, 0x9, 0x2c, 0x13, 0x81, 0x40, 0x7, 0x8a, 0x5f, 0x6c, 0xb0, 0x91, 0x4f, 0x33, 0x6e, 0x70, 0x90, 0x0, 0xa8, 0x7c, 0x8d, 0xe4, 0x97, 0xdd, 0xb8, 0x79, 0xfa, 0x21, 0x3e, 0x1d, 0xb4, 0xfd, 0x4d, 0xed, 0x25, 0xfe, 0xfd, 0xb6, 0x11, 0xfc, 0x6d, 0x86, 0x13, 0x5c, 0x5f, 0xf2, 0xc6, 0xcf, 0x17, 0x1c, 0x0, 0xb0, 0xc8, 0xc3, 0xc1, 0x9f, 0x18, 0x59, 0x19, 0x7d, 0x5a, 0x54, 0x58, 0x42, 0x7d, 0x4b, 0xf8, 0xa9, 0x33, 0x4d, 0xa9, 0x68, 0x24, 0x52, 0x3f, 0x6f, 0x45, 0x84, 0xc, 0x8f, 0x87, 0xea, 0x2a, 0xaf, 0x16, 0xb8, 0xac, 0x4, 0x25, 0x56, 0xc9, 0x44, 0xba, 0xa9, 0x83, 0x32, 0xff, 0xa1, 0xb6, 0x17, 0x6, 0xd5, 0xff, 0x17, 0x59, 0x5f, 0xe0, 0xce, 0xdd, 0x5b, 0xec, 0x21, 0x39, 0x5f, 0x5d, 0x4a, 0xd3, 0x8f, 0xbb, 0x2f, 0xa4, 0x1d, 0xfb, 0xc9, 0xd6, 0xe, 0x1e, 0xce, 0x6, 0x4, 0xb7, 0x42, 0x54, 0x95, 0x61, 0xed, 0xd8, 0xa0, 0x8e, 0x82, 0x6d, 0x70, 0x71, 0xdd, 0xad, 0xb4, 0x3, 0xcf, 0xd5, 0x6f, 0xdd, 0x38, 0x62, 0x8b, 0xd6, 0x61, 0x44, 0x8d, 0x70, 0x9f, 0xbd, 0x8e, 0x80, 0xa5, 0x18, 0x68, 0xf4, 0x3f, 0xc7, 0x26, 0x82, 0x36, 0xac, 0xcb, 0x2a, 0x42, 0x64, 0xfe, 0x87, 0xdb, 0x45, 0xfc, 0xcb, 0x4c, 0x12, 0x8, 0x7e, 0x54, 0x46, 0xfd, 0x43, 0xa4, 0x3f, 0xb7, 0xaa, 0x35, 0x93, 0x44, 0x99, 0xf7, 0x37, 0x68, 0x10, 0xd5, 0x1b, 0xfa, 0xe8, 0xfa, 0xe0, 0xfd, 0x4a, 0xa3, 0x86, 0xd6, 0x68, 0xcd, 0x95, 0x31, 0x26, 0xda, 0x34, 0x6d, 0x90, 0x7, 0xaa, 0x61, 0xdf, 0xe0, 0xaa, 0xa0, 0xd, 0x1c, 0xec, 0x2a, 0xb5, 0x95, 0x43, 0x73, 0x8, 0xb5, 0xa9, 0xc3, 0x5d, 0x36, 0xe, 0x4e, 0x38, 0x95, 0x9a, 0x7e, 0x6d, 0xb2, 0xe0, 0xd6, 0x3b, 0x7e, 0xef, 0xdf, 0xdf, 0xbe, 0xe0, 0x3f, 0xd3, 0xcc, 0xc0, 0x79, 0x40, 0x77, 0x19, 0x1a, 0x88, 0xa, 0xef, 0x62, 0x6a, 0x60, 0x18, 0x1a, 0x8, 0x28, 0x94, 0x37, 0xa7, 0x96, 0xa1, 0x81, 0x85, 0x45, 0x7e, 0xb, 0xed, 0x85, 0x53, 0xc3, 0xaf, 0x4f, 0xba, 0x1c, 0xc8, 0xfd, 0x35, 0x1b, 0xa6, 0x6e, 0x63, 0x87, 0x3d, 0x80, 0x30, 0x25, 0x64, 0xf9, 0x2e, 0x7b, 0x0, 0xf7, 0xc2, 0x77, 0x59, 0x4, 0x14, 0xbf, 0x5b, 0x4, 0xfc, 0x8f, 0xb0, 0x8, 0xc8, 0x7f, 0xb7, 0x8, 0xf8, 0xdd, 0x22, 0xe0, 0xb7, 0xb5, 0x8, 0xb0, 0x79, 0xd7, 0xde, 0x9d, 0xfc, 0xef, 0xbf, 0xd4, 0x2a, 0xa0, 0xf8, 0xdf, 0x60, 0x15, 0x20, 0x4d, 0xbf, 0xf1, 0xbd, 0xe9, 0x5f, 0x69, 0xd, 0x70, 0x4f, 0xfe, 0xeb, 0x2e, 0x8b, 0x0, 0x79, 0xcb, 0xf9, 0xe, 0xf7, 0xfe, 0x3b, 0x6f, 0xe9, 0x77, 0xf0, 0x6d, 0xee, 0xb2, 0x4e, 0xd6, 0xea, 0xdf, 0x72, 0x55, 0x2f, 0x17, 0xf4, 0x5d, 0x2f, 0xeb, 0xff, 0xed, 0x37, 0xeb, 0x66, 0x50, 0x12, 0x4d, 0x77, 0xed, 0x17, 0xcb, 0xd5, 0x9b, 0x4, 0x20, 0x62, 0x90, 0xb8, 0x45, 0xfb, 0xbc, 0xb5, 0x2c, 0x29, 0x85, 0x4d, 0xad, 0x66, 0x7b, 0x66, 0x20, 0xdc, 0x7d, 0xd, 0x53, 0xfa, 0x6e, 0xc1, 0xd7, 0xa8, 0x62, 0xcd, 0x21, 0xf7, 0xf6, 0xb6, 0x42, 0xe3, 0xca, 0x9d, 0x75, 0x9e, 0xae, 0xf9, 0x65, 0x6, 0xa2, 0x5d, 0xb3, 0xde, 0x7b, 0x5c, 0xf8, 0x2b, 0x4f, 0x48, 0x3e, 0x78, 0x43, 0x8d, 0x69, 0x1e, 0x2b, 0xf, 0xc6, 0xdd, 0x6c, 0x57, 0xdb, 0x14, 0xc0, 0x56, 0x2a, 0xde, 0x79, 0x73, 0xdf, 0x75, 0x4c, 0x38, 0xdd, 0xcd, 0x5b, 0x60, 0xa1, 0xad, 0xa9, 0x6a, 0xed, 0x11, 0xe1, 0x33, 0x1c, 0xda, 0x82, 0xb5, 0xfd, 0x94, 0xcb, 0x28, 0xc3, 0x28, 0x5e, 0xd9, 0xc9, 0x42, 0x2b, 0xf8, 0x26, 0x5d, 0xd, 0x29, 0x35, 0xd4, 0x10, 0xdd, 0x51, 0x81, 0xa8, 0xad, 0x8b, 0xa5, 0x60, 0xf0, 0x60, 0x3d, 0x50, 0xf1, 0xd, 0x4, 0x1, 0x8b, 0xf9, 0x78, 0x93, 0xb7, 0x20, 0xad, 0x24, 0x2b, 0xd4, 0x27, 0xc5, 0x76, 0xb6, 0x2a, 0x9, 0x55, 0xe7, 0xe0, 0xfa, 0xd4, 0x71, 0xa0, 0x27, 0x1d, 0x65, 0x5d, 0xb6, 0x13, 0x61, 0x47, 0xd9, 0x13, 0xa3, 0x6c, 0x1d, 0xb5, 0x85, 0x54, 0x9e, 0x77, 0xb6, 0x6d, 0x4, 0x88, 0x6a, 0xd, 0x9b, 0x54, 0xb6, 0xf7, 0x1c, 0xb6, 0x2c, 0x7b, 0xaf, 0x61, 0xcb, 0xb2, 0xf7, 0x1e, 0xb6, 0xa3, 0x6d, 0x63, 0xd8, 0xa, 0x28, 0xca, 0xa6, 0x97, 0xa9, 0xda, 0xd7, 0xb6, 0xa6, 0x8f, 0x95, 0xb6, 0xc7, 0xa9, 0x25, 0xd5, 0x97, 0x76, 0xcc, 0x1e, 0x37, 0x40, 0x65, 0x33, 0x9f, 0x3c, 0x12, 0x83, 0x52, 0xbb, 0x81, 0x62, 0x50, 0x5f, 0x74, 0x60, 0xa6, 0x80, 0x6f, 0xca, 0x76, 0xd9, 0x1, 0x5b, 0xca, 0x19, 0x55, 0xc1, 0xce, 0xd8, 0x86, 0x3c, 0x74, 0x16, 0x75, 0xed, 0x1a, 0x3a, 0x90, 0x3a, 0x77, 0xb3, 0x63, 0xdb, 0xae, 0xba, 0xb6, 0x93, 0xa9, 0x91, 0x8a, 0xd0, 0x74, 0xa5, 0x8e, 0x13, 0xa5, 0x92, 0xf5, 0x7a, 0xd6, 0xae, 0xaa, 0x8e, 0xe5, 0x44, 0xe9, 0xfe, 0xe0, 0x60, 0xa1, 0x1f, 0x15, 0xc5, 0x40, 0x67, 0xaa, 0xa9, 0xc5, 0x59, 0x7d, 0xc6, 0xce, 0x55, 0xb0, 0x63, 0x1b, 0x28, 0xd4, 0x7e, 0x51, 0xe9, 0xe1, 0x8e, 0x42, 0x86, 0xef, 0xa9, 0xa9, 0x94, 0xb1, 0xbc, 0xc4, 0x4b, 0x19, 0xe3, 0xd8, 0xb9, 0x5d, 0x88, 0x91, 0xe4, 0x53, 0x6a, 0xff, 0x14, 0x6b, 0x1e, 0x8b, 0x1b, 0x53, 0x8e, 0xe4, 0x5a, 0xff, 0xfd, 0xc8, 0xf4, 0x10, 0x97, 0xc, 0xe4, 0xf1, 0x83, 0x7, 0x4c, 0xfd, 0x37, 0x1c, 0xfc, 0x97, 0x56, 0xae, 0xbb, 0xfc, 0x18, 0x1f, 0x35, 0x5c, 0xb9, 0xc3, 0x63, 0x67, 0xfa, 0xf7, 0x2a, 0x9d, 0x46, 0x2, 0xeb, 0x6a, 0xda, 0x14, 0xfd, 0x1a, 0x43, 0xa3, 0xdf, 0xed, 0x89, 0xfe, 0x69, 0xf6, 0x44, 0x4f, 0x8b, 0x65, 0xbc, 0xc6, 0x98, 0x13, 0xef, 0x6f, 0x50, 0xd4, 0x69, 0xed, 0xf3, 0xef, 0x37, 0x37, 0x70, 0x2a, 0xd1, 0xeb, 0x2b, 0xc0, 0xe1, 0x7b, 0x58, 0x1f, 0x99, 0x8c, 0xbc, 0x11, 0x6, 0xab, 0x7e, 0x30, 0xcc, 0x2d, 0x1, 0xbd, 0x83, 0xf2, 0xe2, 0x3e, 0x6a, 0x90, 0xfb, 0x28, 0x38, 0x74, 0xc0, 0x84, 0x9d, 0x8a, 0x97, 0xfb, 0xa, 0x78, 0xad, 0x30, 0x15, 0xbb, 0x8a, 0xab, 0x32, 0xcc, 0x8a, 0x4d, 0xe1, 0xd2, 0xa8, 0x58, 0xb1, 0x2b, 0x9a, 0x21, 0x23, 0x76, 0x54, 0xd0, 0x51, 0x29, 0x9a, 0xc1, 0x28, 0xee, 0xae, 0xf3, 0xfd, 0x4e, 0xe5, 0x84, 0xc2, 0x5d, 0x93, 0x1d, 0x7a, 0xb, 0x0, 0x9c, 0xfb, 0x69, 0x2e, 0x64, 0xf4, 0x9, 0xc4, 0x3f, 0x1d, 0xa, 0xb3, 0x4e, 0x59, 0x41, 0x6, 0x73, 0x70, 0xc2, 0x67, 0x3b, 0x4b, 0x47, 0xef, 0x77, 0x2a, 0xe0, 0xee, 0xa5, 0xea, 0x73, 0xe9, 0xc3, 0xb6, 0x96, 0xf4, 0x63, 0x68, 0xa6, 0x2a, 0x4b, 0x4c, 0x6b, 0xa9, 0x94, 0xdf, 0xd5, 0xec, 0xec, 0x77, 0x93, 0xbe, 0xa6, 0x49, 0xdf, 0xff, 0x7a, 0x43, 0xbc, 0xf7, 0xb3, 0x70, 0xb3, 0x6e, 0x9a, 0xd8, 0xaf, 0x30, 0xe6, 0x6b, 0x8, 0x7f, 0x76, 0xb4, 0x13, 0x25, 0x28, 0xbe, 0xab, 0xd9, 0x9a, 0x68, 0xb4, 0x19, 0xc6, 0xe, 0x79, 0x47, 0xa7, 0x59, 0xdc, 0xfd, 0xc, 0xd7, 0xfe, 0x8d, 0x56, 0x55, 0xbf, 0x99, 0x95, 0x9b, 0xd6, 0x47, 0xb4, 0x34, 0x40, 0x6, 0x56, 0x8a, 0x5c, 0x83, 0x57, 0x97, 0x5d, 0x35, 0x6e, 0x72, 0x9e, 0x8e, 0xb1, 0x73, 0x8, 0xa, 0xb6, 0xf5, 0xe5, 0xc8, 0xb8, 0x1d, 0xba, 0xc1, 0x56, 0x56, 0x4e, 0x6e, 0xfe, 0xe7, 0x6a, 0x22, 0x43, 0xf7, 0x25, 0x3, 0x9c, 0xdc, 0xfb, 0xdb, 0xa9, 0x29, 0xb, 0xef, 0xfb, 0x5e, 0x17, 0x3c, 0x6a, 0x5e, 0x54, 0x74, 0x5e, 0x92, 0x34, 0x6e, 0x2d, 0x44, 0x1, 0x56, 0xb2, 0x1b, 0x8c, 0x2a, 0x13, 0xbe, 0xc3, 0x10, 0xdf, 0x93, 0x72, 0x6e, 0x7f, 0xb, 0x93, 0xca, 0x7b, 0x1a, 0x44, 0x9a, 0xa7, 0xc9, 0x34, 0x8f, 0xfc, 0xd7, 0xd8, 0x28, 0xb6, 0x89, 0xb9, 0x3d, 0xa1, 0xe, 0xc2, 0xde, 0xda, 0x9b, 0x9b, 0xf7, 0x5d, 0xe8, 0x5f, 0x65, 0xc7, 0x78, 0x1f, 0xc4, 0x7c, 0xf, 0xe3, 0xc4, 0xa6, 0xe, 0xf5, 0x37, 0xb1, 0x4d, 0xec, 0xc4, 0xef, 0xef, 0x37, 0x8b, 0x77, 0xb1, 0x34, 0xfc, 0xd7, 0x18, 0x18, 0x6a, 0x83, 0x46, 0x7, 0xa6, 0x96, 0x19, 0xbf, 0x91, 0x56, 0xc3, 0x2d, 0xad, 0xc2, 0x12, 0x5a, 0x21, 0x78, 0x6e, 0x5a, 0xea, 0x6, 0x8a, 0x3d, 0xa2, 0x12, 0xbe, 0xd9, 0x54, 0x96, 0xd, 0xa0, 0x94, 0x73, 0xf6, 0x47, 0x4e, 0x55, 0x87, 0x1d, 0xee, 0xcd, 0x36, 0x3e, 0x1c, 0x5, 0x1e, 0xb3, 0x3, 0xba, 0x29, 0x4b, 0xbf, 0x46, 0xa4, 0xb2, 0xd0, 0xfb, 0xe8, 0xe1, 0x1a, 0x84, 0xc2, 0x8f, 0x3c, 0xe6, 0x88, 0x70, 0x16, 0x7a, 0x79, 0xb1, 0xbe, 0x88, 0x97, 0xad, 0x4c, 0xc4, 0x71, 0xa3, 0x21, 0x73, 0x4, 0x35, 0xb, 0xbd, 0x3f, 0x7e, 0xf2, 0xc9, 0x27, 0xde, 0x2e, 0x4b, 0xc4, 0x8f, 0x7f, 0xb7, 0x44, 0xfc, 0x67, 0x59, 0x22, 0xfe, 0x6f, 0xb3, 0x31, 0xec, 0x34, 0x1, 0x34, 0x4d, 0x9d, 0x82, 0xdf, 0xad, 0x2, 0x7f, 0xb7, 0xa, 0xec, 0xb0, 0xa, 0xa4, 0x10, 0x8c, 0xe6, 0x55, 0x9f, 0x56, 0xd4, 0x82, 0x20, 0x53, 0x44, 0x36, 0x99, 0xb4, 0x23, 0x4c, 0xe6, 0xec, 0x4e, 0xd2, 0xc8, 0x83, 0x0, 0x15, 0xed, 0xbf, 0xb5, 0xe1, 0xe1, 0x95, 0x4b, 0x76, 0x83, 0xcf, 0x89, 0x31, 0x20, 0xc5, 0xec, 0x14, 0x20, 0x19, 0x5f, 0xdf, 0xa3, 0xfc, 0xb5, 0x2e, 0x7f, 0xfd, 0x3f, 0xc9, 0xb0, 0xb1, 0xc3, 0xa2, 0xf0, 0xdf, 0x68, 0xa5, 0xd7, 0x19, 0x5, 0x48, 0x2a, 0x3c, 0x88, 0x33, 0xf9, 0x6c, 0x5d, 0x5c, 0x88, 0x50, 0xd8, 0xb6, 0x55, 0x65, 0x1d, 0xe3, 0xb9, 0xbd, 0x35, 0xc4, 0x5f, 0xe5, 0xcd, 0x70, 0xd4, 0x2d, 0xb1, 0x93, 0x15, 0xe6, 0x93, 0x30, 0xbe, 0xc, 0xec, 0xda, 0x37, 0x79, 0xab, 0xa3, 0x3c, 0x60, 0x71, 0x6d, 0x8d, 0xe7, 0x17, 0xa7, 0x91, 0xbb, 0xad, 0xdb, 0xdb, 0xe1, 0x69, 0x81, 0xbe, 0xe9, 0x45, 0x34, 0x44, 0x40, 0x6, 0xb4, 0x4e, 0x11, 0x36, 0x4f, 0xa2, 0x6, 0x23, 0x25, 0x3, 0x41, 0xeb, 0xbb, 0xe4, 0xee, 0x1b, 0xf2, 0x58, 0xc9, 0xb0, 0x62, 0x85, 0xcf, 0xa, 0xc2, 0x68, 0x71, 0xa7, 0x45, 0xe1, 0xef, 0x4a, 0xec, 0xdf, 0x95, 0xd8, 0xef, 0xa6, 0xc4, 0x6e, 0xf0, 0xc5, 0xd, 0xd4, 0x37, 0x77, 0x16, 0x75, 0xc, 0xac, 0xc9, 0x99, 0x4f, 0xdc, 0xd, 0xa9, 0xb1, 0xb9, 0x58, 0xe1, 0x36, 0x53, 0x63, 0x17, 0x70, 0x71, 0xd5, 0x3b, 0xea, 0x10, 0x20, 0x3a, 0x99, 0xf8, 0x1d, 0x95, 0x24, 0x5c, 0xba, 0x98, 0xfb, 0x5d, 0x5d, 0xd1, 0xc1, 0x78, 0x57, 0x6b, 0xda, 0x7f, 0xf9, 0x1d, 0xc0, 0x52, 0x9e, 0x21, 0xf5, 0xb2, 0xad, 0x7d, 0x27, 0xa0, 0xb9, 0xe6, 0xe1, 0x39, 0x7d, 0x37, 0x2e, 0x9, 0xa4, 0x51, 0x84, 0xe3, 0xf1, 0x91, 0xb6, 0xc6, 0x41, 0xb7, 0x65, 0xd5, 0x6d, 0x3e, 0x52, 0x72, 0xf, 0xd5, 0x5e, 0xc3, 0xc, 0x2b, 0x33, 0x6c, 0xa2, 0xdd, 0x5a, 0x47, 0xea, 0x79, 0x92, 0x1, 0xc7, 0x9e, 0x14, 0x79, 0x12, 0x57, 0x72, 0x2c, 0x41, 0xb8, 0xcb, 0x8e, 0xbb, 0xa5, 0x28, 0x44, 0xf, 0xbb, 0x2d, 0x2a, 0x6e, 0x7f, 0xd7, 0x15, 0xfe, 0xe7, 0xe8, 0xa, 0x3b, 0xd, 0x2a, 0x3b, 0xec, 0x1b, 0x7b, 0xac, 0xc3, 0xd2, 0xd2, 0xd0, 0x2, 0x77, 0xf0, 0xaa, 0x1d, 0xac, 0xc2, 0xdd, 0xba, 0x1d, 0xf5, 0x52, 0xef, 0xaf, 0xb4, 0xe3, 0x2c, 0x89, 0xb, 0x2d, 0x1b, 0xbc, 0xe5, 0x3f, 0xd5, 0x16, 0x73, 0x69, 0xbc, 0xe8, 0x93, 0xdd, 0xe9, 0x6e, 0x7d, 0x87, 0x6d, 0xa6, 0xe3, 0x71, 0x5f, 0xab, 0x17, 0xf5, 0x12, 0xf0, 0xaf, 0x33, 0xda, 0xec, 0x1a, 0x5e, 0x87, 0x9e, 0xf7, 0xde, 0xbe, 0x2b, 0xef, 0xa7, 0xbf, 0x95, 0x5a, 0xd3, 0x77, 0xbd, 0x8, 0xfe, 0x97, 0xe9, 0xbf, 0x77, 0x69, 0x87, 0x9d, 0xe8, 0xda, 0x85, 0xea, 0xdd, 0x88, 0x7c, 0x87, 0x16, 0x96, 0x35, 0xd, 0x57, 0x6d, 0xb5, 0x6c, 0x4b, 0xc1, 0xc8, 0x7e, 0x85, 0x43, 0xce, 0x1d, 0x96, 0xa1, 0xbb, 0xe, 0x3c, 0x67, 0xf7, 0xd6, 0xdb, 0x6, 0x86, 0x91, 0xe8, 0x3f, 0xd5, 0x1e, 0xd0, 0x35, 0x43, 0xc0, 0x76, 0xe2, 0x95, 0x82, 0x96, 0x4d, 0x60, 0xb8, 0xc3, 0xc8, 0xce, 0xb6, 0x63, 0xd3, 0x26, 0x77, 0xdd, 0x86, 0x6f, 0xc2, 0xd4, 0x8d, 0xed, 0xf6, 0x7d, 0xb2, 0x17, 0x7a, 0xb7, 0xf9, 0xdb, 0xf8, 0xf, 0x47, 0x47, 0x8f, 0x8a, 0xa2, 0x82, 0xbe, 0xe3, 0xd5, 0xe0, 0x55, 0xf9, 0x87, 0x9e, 0x6e, 0x2b, 0x6e, 0xa8, 0x8e, 0x55, 0xc6, 0x5e, 0xe2, 0x27, 0x2c, 0xb5, 0xe3, 0x8d, 0xd3, 0x70, 0x1a, 0x3c, 0x1, 0x59, 0x39, 0xa, 0x65, 0x34, 0x48, 0x8c, 0xb8, 0xf0, 0xbe, 0x37, 0xc5, 0xe5, 0x49, 0xe3, 0xa5, 0x17, 0xb0, 0x79, 0x14, 0x6b, 0xb5, 0x1d, 0x48, 0x4d, 0x83, 0x4f, 0x9f, 0x7c, 0xf6, 0xf0, 0xdb, 0x2f, 0x5f, 0x3c, 0x67, 0xb2, 0x6c, 0xc0, 0x5a, 0x4f, 0x13, 0x24, 0x7, 0x7, 0x49, 0x30, 0x9e, 0xdd, 0xde, 0xb6, 0x9a, 0x83, 0x2e, 0x10, 0x83, 0x4f, 0x85, 0xe6, 0x6b, 0xe, 0xb0, 0x80, 0xda, 0x26, 0x60, 0xb9, 0x8c, 0xca, 0x93, 0xd9, 0x59, 0x72, 0xee, 0xa7, 0x41, 0x38, 0x27, 0xc9, 0xea, 0xe0, 0x60, 0x46, 0x7f, 0x21, 0x65, 0x2b, 0x9e, 0xe0, 0x98, 0xd6, 0x5c, 0xcd, 0x94, 0x25, 0x12, 0x39, 0x49, 0xc0, 0x89, 0x12, 0x1, 0x88, 0x1f, 0x4c, 0x8b, 0xf4, 0x1a, 0x26, 0x96, 0x16, 0xc9, 0x86, 0x1e, 0xdf, 0xc3, 0xdf, 0xf2, 0xb8, 0x7c, 0xc0, 0x85, 0x1f, 0x1f, 0x64, 0x4f, 0x55, 0x12, 0xca, 0x78, 0xc5, 0x3c, 0xb2, 0xf2, 0xc9, 0x5c, 0xdb, 0xf7, 0xc4, 0xd0, 0xfb, 0xa2, 0x84, 0xa7, 0x2a, 0x28, 0x91, 0x24, 0x22, 0xfd, 0x93, 0x70, 0x32, 0x2a, 0x91, 0x7d, 0xcf, 0x8d, 0x94, 0x62, 0x9d, 0x1, 0x54, 0xc6, 0xcb, 0x47, 0xd0, 0x39, 0x8, 0x26, 0x46, 0x4e, 0x99, 0xac, 0x8b, 0xe5, 0x72, 0x2a, 0x23, 0x9d, 0xa9, 0xa7, 0x86, 0xb3, 0x79, 0x5e, 0xac, 0x6b, 0x79, 0x69, 0x99, 0x25, 0xaf, 0xa3, 0xfd, 0x91, 0x4d, 0xed, 0x91, 0x76, 0x54, 0x5c, 0x3e, 0xf5, 0xec, 0x1e, 0x2a, 0x9a, 0x94, 0x42, 0xa2, 0x17, 0xc, 0x96, 0x45, 0x9c, 0xfa, 0x8e, 0xea, 0x2c, 0xc6, 0x3b, 0xb2, 0xab, 0x6b, 0xbf, 0x89, 0xe3, 0x75, 0x83, 0xb0, 0x2b, 0x73, 0xe0, 0x27, 0x7c, 0xf, 0x9b, 0xe0, 0xe9, 0xa0, 0x86, 0x8, 0xfd, 0xd4, 0xe1, 0x78, 0x3a, 0xf8, 0xc7, 0x93, 0x67, 0xcf, 0xbf, 0xf8, 0xe6, 0xeb, 0xc8, 0xfb, 0x78, 0xf0, 0xf1, 0xe0, 0x4f, 0x1e, 0x80, 0xc7, 0x8b, 0x67, 0xf, 0xbf, 0x7e, 0xfe, 0xc5, 0xb, 0x48, 0xfc, 0xf9, 0xd3, 0x6f, 0x9f, 0x3d, 0xc4, 0x8f, 0xe8, 0xe3, 0xe1, 0x10, 0x72, 0x1e, 0x3d, 0x7c, 0xfc, 0xb7, 0x4f, 0x9f, 0x7d, 0xf3, 0xf4, 0x67, 0x57, 0x91, 0xd1, 0x83, 0xa1, 0x1, 0x5b, 0xd1, 0xcd, 0xd4, 0xb0, 0xd1, 0x7c, 0xcd, 0xaf, 0xa7, 0x45, 0xbc, 0x4e, 0xe9, 0xae, 0x2, 0x56, 0x18, 0xfe, 0x22, 0x20, 0xd6, 0xe1, 0xb1, 0xab, 0x62, 0x8e, 0x17, 0x31, 0xe6, 0x89, 0x30, 0x81, 0x5e, 0xee, 0x8b, 0x7c, 0xc0, 0x1e, 0x38, 0x4f, 0x5f, 0x3d, 0xa, 0x88, 0x60, 0x15, 0x7, 0x76, 0x63, 0x98, 0x58, 0x37, 0x95, 0x88, 0x33, 0x92, 0x8a, 0xab, 0x18, 0x38, 0x2a, 0x3, 0xa1, 0x5d, 0xf5, 0xb0, 0x58, 0xbd, 0x28, 0xc, 0x3a, 0x44, 0x84, 0x97, 0xbe, 0x88, 0xd7, 0x80, 0x1b, 0xc3, 0x44, 0x39, 0x2d, 0xb4, 0xd6, 0x93, 0x7, 0x16, 0xb0, 0xe0, 0x19, 0xc9, 0xca, 0x4f, 0xc5, 0x85, 0xd, 0xba, 0x6, 0x20, 0xc6, 0x4c, 0xfd, 0x40, 0x99, 0x35, 0x28, 0x98, 0xda, 0x1f, 0x2a, 0x5a, 0xc6, 0x93, 0xd7, 0xcf, 0x15, 0xf0, 0x68, 0x2, 0x80, 0x94, 0xa6, 0x91, 0x46, 0x27, 0x0, 0xad, 0x8a, 0x4, 0x93, 0xe4, 0x9, 0xd0, 0x28, 0x56, 0x3c, 0x57, 0x30, 0xcc, 0x1, 0x5b, 0xaf, 0x78, 0x4d, 0xa8, 0x4b, 0x83, 0x4e, 0xe9, 0x71, 0xc3, 0x1a, 0x78, 0x9, 0x2, 0x22, 0x2a, 0x63, 0x2e, 0xb2, 0xb2, 0x34, 0x26, 0xfd, 0xd1, 0x19, 0x1e, 0xef, 0xbe, 0xcc, 0x88, 0x44, 0x17, 0xde, 0xf9, 0x47, 0x1a, 0xba, 0xf4, 0x8a, 0x4b, 0x90, 0xb1, 0xe, 0x1b, 0x35, 0x4d, 0xea, 0xec, 0x14, 0x66, 0xe8, 0x68, 0xde, 0x80, 0xcd, 0xd4, 0x1c, 0x10, 0x97, 0xd5, 0x36, 0xab, 0x5d, 0x95, 0xa6, 0xc1, 0xd, 0x9c, 0xef, 0x41, 0x45, 0x1b, 0x12, 0xc0, 0x42, 0xfa, 0x75, 0x23, 0xa8, 0x62, 0x4a, 0xdd, 0xa7, 0x6d, 0x28, 0xa4, 0x17, 0xeb, 0x89, 0x26, 0x7, 0xc6, 0x1c, 0x94, 0x9b, 0x15, 0xbe, 0xaf, 0x62, 0xd0, 0xc7, 0x83, 0x3, 0x63, 0x94, 0x80, 0xdb, 0xe5, 0xba, 0xcf, 0xe0, 0xf8, 0x78, 0xc1, 0xd8, 0xc8, 0x5b, 0xc5, 0x6b, 0x4, 0xa1, 0x40, 0xca, 0x87, 0xb7, 0xb7, 0x46, 0x5e, 0xbc, 0x5a, 0xe1, 0x1d, 0x52, 0x81, 0x83, 0x15, 0x28, 0xcb, 0xc8, 0x24, 0x78, 0xd, 0x24, 0xee, 0x78, 0x1, 0xe3, 0x1a, 0x62, 0x76, 0x9c, 0xbe, 0xda, 0x94, 0xd5, 0xa7, 0xb4, 0xa6, 0x48, 0x73, 0xcc, 0x71, 0xa0, 0x28, 0x2a, 0xde, 0xce, 0x10, 0x34, 0xd4, 0xec, 0x49, 0x43, 0x46, 0x6, 0x10, 0x31, 0x88, 0xab, 0xa, 0xe, 0x7b, 0xbc, 0xce, 0xe2, 0x3e, 0x6c, 0x58, 0xa, 0x50, 0xc2, 0xf6, 0x47, 0xd8, 0x3c, 0xcf, 0x67, 0xc5, 0x3a, 0x1, 0xc1, 0x24, 0xd9, 0x94, 0xd2, 0x97, 0x66, 0x66, 0x1f, 0x83, 0x7c, 0xf7, 0x39, 0xe0, 0x93, 0xd4, 0xd8, 0x72, 0x8e, 0xd4, 0xe0, 0x85, 0x5e, 0xb4, 0x27, 0x79, 0xda, 0xb5, 0xd1, 0x1a, 0x3, 0xcd, 0xb0, 0x6b, 0x18, 0xa2, 0x4a, 0x98, 0xc1, 0x6, 0xd, 0xf8, 0x85, 0x30, 0x39, 0x30, 0x5b, 0xf2, 0x9d, 0xe8, 0x27, 0x8, 0xef, 0xdb, 0x68, 0x3, 0x13, 0x20, 0xe0, 0x5a, 0x98, 0x0, 0xe9, 0x1a, 0xe4, 0xd3, 0x21, 0x95, 0x47, 0xd6, 0xc7, 0x17, 0xa, 0xf5, 0x6a, 0x60, 0xd, 0x3, 0x53, 0x32, 0x37, 0xa, 0x48, 0x6c, 0x14, 0x70, 0x70, 0xb0, 0x9f, 0x38, 0x71, 0x80, 0xba, 0x79, 0xd6, 0x38, 0x60, 0xb4, 0xf3, 0xdc, 0xd6, 0xc4, 0x2e, 0xc0, 0x3d, 0x97, 0x53, 0xcc, 0xf2, 0xee, 0x1, 0x9, 0x31, 0xe4, 0x2e, 0x28, 0x18, 0xca, 0xe6, 0x3a, 0xb0, 0x80, 0xcc, 0xed, 0x3c, 0x91, 0xcd, 0x43, 0xaf, 0xb, 0xbb, 0x4f, 0x3d, 0xcc, 0xc3, 0x79, 0xb6, 0xec, 0x91, 0x37, 0x8f, 0xd7, 0xa4, 0x89, 0xb4, 0x5c, 0x60, 0xd6, 0xc2, 0x4a, 0x5f, 0x61, 0x8f, 0x12, 0x35, 0xbd, 0x13, 0x40, 0xd9, 0x2d, 0xf8, 0x4d, 0xc0, 0x31, 0x8f, 0x8c, 0xa9, 0x81, 0xb9, 0xc7, 0xe, 0x11, 0x52, 0x6c, 0x25, 0xb7, 0xc9, 0x75, 0xdc, 0xa0, 0xd7, 0x70, 0xd0, 0xf1, 0xb5, 0x2d, 0x89, 0xee, 0xa4, 0x85, 0xa1, 0xb9, 0x5c, 0x7e, 0xac, 0x51, 0xa1, 0x42, 0x3b, 0x1d, 0x4, 0x5f, 0x9e, 0xc, 0x4d, 0xe6, 0xed, 0xa9, 0x11, 0xec, 0x45, 0x4d, 0xb6, 0x41, 0x83, 0xb2, 0xc5, 0x6b, 0x28, 0xc2, 0x3d, 0x69, 0x93, 0x14, 0xc8, 0xea, 0xc0, 0xfa, 0xae, 0xa9, 0x1e, 0xff, 0x17, 0xce, 0xed, 0xcd, 0x22, 0x4b, 0x16, 0xb2, 0xb, 0x41, 0xc6, 0xd5, 0x18, 0x43, 0x9b, 0xa4, 0x36, 0xba, 0xc3, 0x95, 0xee, 0xec, 0xaf, 0x31, 0x3f, 0x71, 0x9a, 0xba, 0xe6, 0x37, 0x89, 0xe5, 0x9b, 0x62, 0x62, 0x9f, 0x44, 0x61, 0xc7, 0xd8, 0xc5, 0x10, 0xe3, 0x3c, 0x5d, 0xf2, 0x6f, 0x49, 0x5e, 0x54, 0xe3, 0x34, 0xea, 0xe3, 0xa8, 0x9a, 0xd, 0x38, 0x10, 0x10, 0x41, 0x58, 0x53, 0x8d, 0x27, 0x1e, 0x29, 0x6a, 0x70, 0x18, 0x62, 0x49, 0xba, 0x29, 0x57, 0x2c, 0x59, 0x2, 0xeb, 0xd4, 0x5b, 0x5c, 0x41, 0x8c, 0xd3, 0xe7, 0xd5, 0x43, 0x22, 0x28, 0x64, 0xec, 0xe2, 0xeb, 0x44, 0x93, 0xbf, 0x88, 0x1d, 0x50, 0x23, 0xd0, 0x85, 0x39, 0x95, 0xd6, 0xca, 0x62, 0xb7, 0x8a, 0xda, 0xb6, 0x56, 0x58, 0x33, 0xd4, 0xea, 0xa8, 0xab, 0xdf, 0xb2, 0xa2, 0xef, 0x64, 0xbc, 0xed, 0x2e, 0xa6, 0xad, 0xc6, 0x9b, 0xec, 0xdb, 0x1d, 0x58, 0x44, 0xfc, 0xd, 0x3d, 0x4f, 0x3f, 0x22, 0xea, 0x6, 0xec, 0xa9, 0xf5, 0x14, 0xe5, 0xac, 0x83, 0x1d, 0xe0, 0xba, 0x95, 0x7a, 0xd0, 0xb1, 0xff, 0xd1, 0x49, 0x9a, 0x5d, 0x2a, 0xbb, 0x10, 0xb1, 0xfc, 0x2a, 0x77, 0xef, 0xa3, 0x1e, 0xef, 0x7d, 0xe4, 0xed, 0x1d, 0x9d, 0x7e, 0x14, 0xd4, 0x9c, 0x40, 0xcd, 0xcd, 0xbd, 0xb, 0x6f, 0xe6, 0x3a, 0x46, 0x16, 0x53, 0xdc, 0x66, 0x7e, 0x26, 0xfe, 0x2e, 0x21, 0xe4, 0xb2, 0xc8, 0xd2, 0xbd, 0x61, 0x10, 0x6a, 0x44, 0x42, 0xf8, 0x26, 0xd9, 0xac, 0x91, 0x99, 0x11, 0xe4, 0x1e, 0x8, 0x16, 0x88, 0x73, 0x71, 0x95, 0x25, 0x5e, 0x14, 0x39, 0x17, 0x6c, 0xd2, 0x44, 0x5a, 0x83, 0x99, 0xe0, 0x2b, 0x42, 0xe3, 0x54, 0x7, 0xaa, 0x2f, 0x75, 0xbc, 0xd9, 0xac, 0x9, 0x14, 0x4d, 0xbe, 0xa6, 0x1, 0x32, 0x36, 0x6f, 0xc3, 0xf6, 0x13, 0xf9, 0xf4, 0xc8, 0x78, 0x36, 0x69, 0x94, 0x74, 0x53, 0x8a, 0xa4, 0x93, 0x1c, 0xec, 0x12, 0x62, 0x82, 0x30, 0xf1, 0xa5, 0xc3, 0x1e, 0x6c, 0xfc, 0xbe, 0x3, 0x7e, 0x3e, 0xa8, 0x1, 0xc7, 0x9, 0xe4, 0xc6, 0xa0, 0x89, 0xd1, 0x9a, 0x47, 0x16, 0x6b, 0x64, 0x1f, 0x21, 0x64, 0x3d, 0x80, 0x21, 0x81, 0x2e, 0xc7, 0xbf, 0x82, 0x64, 0xde, 0xb1, 0x12, 0xf3, 0xf7, 0x5c, 0x89, 0xb9, 0x5a, 0x9, 0x39, 0x44, 0x1b, 0xaf, 0x19, 0x98, 0xb1, 0x85, 0x8, 0x6c, 0x76, 0xd6, 0xae, 0x68, 0xe6, 0xb9, 0x71, 0xa2, 0x5, 0x5b, 0x82, 0x51, 0xfe, 0x9c, 0x34, 0x78, 0xa7, 0x5a, 0x13, 0xa0, 0x3e, 0x64, 0x34, 0x9f, 0x1, 0x9c, 0x20, 0xf8, 0x23, 0x4a, 0x35, 0x50, 0x6a, 0x82, 0xda, 0x65, 0x19, 0x40, 0xe2, 0x4b, 0x3e, 0xab, 0x42, 0xb1, 0xa9, 0x78, 0x16, 0xbf, 0x28, 0xf1, 0x1e, 0x3, 0x35, 0x9a, 0x90, 0x77, 0x70, 0x10, 0x4f, 0x1c, 0x62, 0x3d, 0x20, 0x12, 0x15, 0x7e, 0xe2, 0x59, 0xad, 0xbd, 0x74, 0xd4, 0xde, 0xef, 0xaa, 0xde, 0x46, 0xa2, 0x36, 0x7e, 0x8e, 0x3a, 0xe5, 0xf7, 0xd6, 0xd0, 0x9b, 0x63, 0x69, 0x37, 0x6e, 0xcb, 0x96, 0xed, 0xf5, 0x15, 0xa4, 0x4b, 0xb8, 0xa8, 0xd2, 0x0, 0x11, 0xbf, 0xed, 0xc7, 0x22, 0x7b, 0x1a, 0x75, 0x2e, 0x30, 0xbe, 0x69, 0x84, 0xc6, 0x1, 0xd0, 0xf5, 0x63, 0x5a, 0x6b, 0x7a, 0x7d, 0x37, 0x18, 0xc7, 0xd1, 0x74, 0x40, 0xf, 0x81, 0xf6, 0x75, 0x14, 0xd7, 0xe9, 0x0, 0x1f, 0x8, 0xd, 0xb6, 0xee, 0x85, 0x8a, 0x2c, 0x6d, 0x8e, 0xdc, 0x38, 0x1a, 0xc9, 0x49, 0xec, 0x54, 0xab, 0x88, 0x77, 0x57, 0xc5, 0x2b, 0xc1, 0x6, 0x1, 0x6b, 0x8, 0xfc, 0x6, 0x71, 0x6b, 0x4f, 0x1a, 0x84, 0xb5, 0x12, 0x2f, 0x57, 0xc, 0x34, 0x4c, 0x6b, 0xeb, 0xc9, 0xc5, 0xec, 0x8b, 0xa7, 0x4c, 0x41, 0x60, 0x1f, 0xb2, 0xd1, 0x50, 0x4a, 0xfd, 0x4d, 0xbd, 0x8f, 0x3d, 0x6e, 0xb2, 0xdb, 0x1b, 0x98, 0x9b, 0x71, 0x7b, 0xb, 0xbb, 0xd3, 0x5, 0x1c, 0xbb, 0x3b, 0x66, 0x71, 0xcf, 0x31, 0x73, 0x17, 0xd8, 0x38, 0x27, 0x79, 0x47, 0xe3, 0xae, 0xd9, 0x34, 0xda, 0x6e, 0x2e, 0x6f, 0x7b, 0x9, 0xf5, 0xec, 0x93, 0x35, 0x87, 0x13, 0x2f, 0xc1, 0xc2, 0xf7, 0x80, 0xe, 0x2, 0x9e, 0x3, 0x1a, 0x82, 0x68, 0xe9, 0xeb, 0xf8, 0x82, 0x2b, 0x7a, 0xa8, 0xe7, 0xd2, 0x97, 0x8d, 0x7b, 0x96, 0x4a, 0x83, 0x8, 0x23, 0xd0, 0xb3, 0xb1, 0x80, 0xbb, 0xd8, 0xa4, 0x4, 0xfd, 0xd8, 0x4, 0x8b, 0xb1, 0x49, 0xf1, 0xa8, 0x36, 0xa2, 0x5, 0x89, 0x6b, 0x17, 0xd9, 0x12, 0x5b, 0x61, 0xd3, 0xed, 0x58, 0xf0, 0x8, 0xf1, 0x60, 0x96, 0xb, 0xf2, 0x39, 0xae, 0x3f, 0xa3, 0x84, 0xd5, 0x3f, 0x6, 0x8f, 0x81, 0x98, 0x55, 0xeb, 0x4d, 0x52, 0x15, 0xeb, 0x68, 0x6a, 0x66, 0xec, 0x7c, 0x56, 0xd5, 0x68, 0x2d, 0xa5, 0x99, 0x6c, 0x6d, 0x61, 0x4d, 0x93, 0x71, 0x45, 0xbe, 0x49, 0x6d, 0xda, 0x8f, 0x57, 0x99, 0xd6, 0xb1, 0x48, 0x15, 0x57, 0xad, 0x62, 0x31, 0xf5, 0x1c, 0x72, 0xf8, 0x52, 0x8b, 0xcb, 0xa3, 0x54, 0xca, 0x71, 0x8b, 0x35, 0x9f, 0x79, 0xa8, 0xd6, 0x85, 0xde, 0x64, 0x92, 0x68, 0x8c, 0xa8, 0x35, 0xc2, 0x2c, 0x45, 0x63, 0x58, 0xf3, 0xd5, 0x32, 0x4e, 0xb8, 0x7f, 0x34, 0x38, 0xf4, 0x27, 0xd1, 0x1f, 0xcf, 0x7e, 0x7a, 0x59, 0x9e, 0xf7, 0x3e, 0x8, 0x8e, 0x98, 0xe7, 0x5, 0xa8, 0xff, 0x9d, 0xb5, 0x94, 0xc2, 0x13, 0x4f, 0x8c, 0xc7, 0xb, 0x6b, 0xdd, 0xb0, 0x50, 0x2c, 0x86, 0xfb, 0x47, 0x7f, 0x3c, 0x1a, 0x54, 0xbc, 0x44, 0x63, 0x34, 0x68, 0x7c, 0xcb, 0x66, 0x4a, 0x4d, 0x9c, 0xca, 0xf, 0xd4, 0x85, 0x64, 0x0, 0x6a, 0xb1, 0x7, 0x5, 0xa6, 0x6d, 0x79, 0x7a, 0x26, 0x48, 0x51, 0x43, 0xc1, 0x66, 0xf2, 0x31, 0x71, 0x87, 0xca, 0x4c, 0xd6, 0x6c, 0xb2, 0xa2, 0xb6, 0x7e, 0x1, 0xbb, 0xe, 0x2f, 0xb3, 0x32, 0x9b, 0xc2, 0xf8, 0x3, 0x54, 0x96, 0xb4, 0x24, 0x1f, 0x54, 0x0, 0x25, 0x42, 0xf9, 0x3e, 0x63, 0x73, 0xa9, 0x8f, 0xf, 0xb6, 0xfe, 0x8f, 0x7c, 0x55, 0x15, 0xc1, 0xf8, 0xff, 0x1, 0xe6, 0x77, 0x53, 0x89, 0x57, 0x48, 0x1, 0x0, 0x0, 0x0, 0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x3, 0x8d, 0x54, 0xc1, 0x72, 0xe3, 0x20, 0xc, 0x3d, 0xa7, 0x33, 0xfd, 0x7, 0x86, 0xbd, 0x2e, 0x71, 0x3b, 0xbd, 0xec, 0xec, 0x62, 0x2e, 0xfd, 0x83, 0xb6, 0x3f, 0x20, 0x63, 0x39, 0x26, 0x8b, 0x6d, 0xa, 0xb2, 0x9b, 0xfc, 0xfd, 0x2, 0xb6, 0x93, 0xb4, 0x9b, 0xce, 0x24, 0x7, 0x47, 0x42, 0xd2, 0xd3, 0x93, 0x90, 0x90, 0x2d, 0x75, 0x56, 0xdd, 0xdf, 0xdd, 0xdf, 0xc9, 0x16, 0xa1, 0x8e, 0x12, 0x63, 0x92, 0xc, 0x59, 0x54, 0xaf, 0x1d, 0x78, 0x62, 0x2f, 0x68, 0xe1, 0x28, 0x8b, 0xf9, 0x28, 0x5b, 0x3b, 0x24, 0x60, 0x2d, 0x91, 0x13, 0xf8, 0x3e, 0x9a, 0xa9, 0xe4, 0xcf, 0x43, 0x4f, 0xd8, 0x93, 0x78, 0x3b, 0x3a, 0xe4, 0x4c, 0xcf, 0x5a, 0xc9, 0x9, 0xf, 0x54, 0x24, 0xf8, 0x3f, 0x4c, 0xb7, 0xe0, 0x3, 0x52, 0x39, 0x52, 0x23, 0x7e, 0x71, 0xc5, 0xce, 0x38, 0x3d, 0x74, 0x58, 0xf2, 0xc9, 0xe0, 0x87, 0x1b, 0x3c, 0x5d, 0x44, 0x7f, 0x98, 0x9a, 0xda, 0xb2, 0xc6, 0xc9, 0x68, 0x14, 0x59, 0xf9, 0xc9, 0x4c, 0x6f, 0xc8, 0x80, 0x15, 0x41, 0x83, 0xc5, 0xf2, 0x91, 0xcf, 0x7c, 0xac, 0xe9, 0xff, 0x32, 0x8f, 0xb6, 0xe4, 0x81, 0x8e, 0x16, 0x43, 0x8b, 0x18, 0x81, 0x5a, 0x8f, 0x4d, 0xc9, 0xab, 0x61, 0xa0, 0x40, 0x1e, 0xdc, 0x56, 0x87, 0xb0, 0x26, 0x2e, 0xce, 0x95, 0x56, 0x43, 0x7d, 0xcc, 0xd2, 0x46, 0xf6, 0x30, 0x31, 0x6d, 0x21, 0x84, 0x92, 0x47, 0xb1, 0x2, 0x2f, 0x4c, 0x3f, 0x61, 0xa4, 0xcd, 0x16, 0xb5, 0xc6, 0x6, 0x46, 0x4b, 0x29, 0xeb, 0x26, 0x86, 0xd6, 0xe6, 0xe4, 0x9f, 0x48, 0x83, 0xe9, 0xd1, 0x8b, 0xc6, 0x8e, 0xa6, 0x5e, 0x3c, 0x3e, 0xfb, 0x2c, 0x20, 0x29, 0x35, 0x7a, 0xae, 0xb2, 0x9d, 0x2d, 0x7e, 0xd1, 0x13, 0xbe, 0xf8, 0x55, 0x1e, 0xfa, 0x7a, 0xad, 0xe2, 0x7, 0x57, 0xb2, 0x80, 0x13, 0x6a, 0x11, 0x61, 0xaf, 0xa5, 0xd0, 0x83, 0xb5, 0xe0, 0xce, 0x84, 0x57, 0x9d, 0x33, 0x53, 0xc7, 0x56, 0x4, 0x81, 0x7, 0xe8, 0x9c, 0x45, 0xf1, 0xc5, 0x2e, 0x96, 0x4e, 0xfe, 0xff, 0x93, 0xa3, 0xbd, 0xe0, 0xb5, 0xe2, 0xc6, 0xbf, 0xef, 0x2, 0xd2, 0x6d, 0x30, 0x15, 0xab, 0x99, 0x89, 0x17, 0x5c, 0xc5, 0xe1, 0x68, 0xcc, 0x2e, 0xd1, 0x97, 0x85, 0x35, 0x37, 0x86, 0x5, 0x87, 0x58, 0xb, 0xc2, 0x10, 0xbb, 0xfd, 0x9a, 0x64, 0xf6, 0x16, 0xe5, 0x5b, 0x40, 0x16, 0xb6, 0xa0, 0xc9, 0x4c, 0xc8, 0x2f, 0x20, 0x35, 0x50, 0x1c, 0x80, 0xe7, 0xf8, 0x3d, 0xc1, 0x5c, 0x5, 0xf9, 0xa6, 0x11, 0xc5, 0x68, 0xd5, 0x8d, 0xce, 0xe7, 0xc3, 0x8b, 0x9b, 0x3a, 0x89, 0xb2, 0x88, 0xed, 0x4b, 0x42, 0x92, 0xaf, 0xcd, 0x50, 0x9e, 0x9e, 0x64, 0xdd, 0xc8, 0xf6, 0xf1, 0xf3, 0x12, 0x46, 0x3d, 0x9f, 0x5f, 0x84, 0x39, 0xd8, 0xe1, 0x69, 0xa8, 0x92, 0x31, 0x85, 0x3d, 0xa9, 0x97, 0xb4, 0x9a, 0x3e, 0xf6, 0xcd, 0x19, 0x4d, 0xa3, 0xc7, 0xc0, 0x86, 0x86, 0xe9, 0x5c, 0x7c, 0xb4, 0x66, 0x90, 0x95, 0xd0, 0x46, 0x9a, 0x6e, 0xc7, 0x82, 0xd7, 0x91, 0x3, 0xd0, 0x76, 0xef, 0x76, 0x9c, 0x15, 0xf9, 0x45, 0x38, 0xfb, 0xe4, 0x8c, 0x69, 0x88, 0x7c, 0x22, 0x32, 0x5f, 0xc, 0xcb, 0xdb, 0x56, 0xf2, 0x48, 0x70, 0x67, 0x7a, 0x51, 0xd, 0x44, 0x43, 0xf7, 0xfb, 0xe9, 0xc1, 0x1d, 0xd2, 0xb4, 0xce, 0x81, 0x29, 0x34, 0x68, 0x6f, 0x1c, 0xcd, 0x9, 0xac, 0xa9, 0xb6, 0xfb, 0xc0, 0x19, 0xc5, 0x97, 0x62, 0x79, 0x20, 0xf6, 0x30, 0xc1, 0xec, 0x92, 0xc2, 0x66, 0x49, 0xa5, 0xfa, 0xe7, 0x55, 0x5d, 0x17, 0x54, 0xe6, 0x97, 0x44, 0xfd, 0x3, 0xd3, 0x6a, 0x6f, 0x20, 0xaf, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};\r\n"
  },
  {
    "path": "app/http/websocket.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n#include \"c_types.h\"\n#include \"user_interface.h\"\n#include \"espconn.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"c_stdio.h\"\n\n#include \"websocket.h\"\n\n\n\nvoid ICACHE_FLASH_ATTR ws_write_frame(ws_frame *frame,write_function w,void *arg){\n\n    uint8_t byte;\n\n    //fin\n    byte = 0x80 ; //set first bit\n    byte |= frame->TYPE; //set op code\n\n    //write first byte\n    w(&byte,1,arg);\n\n    \n    byte=0;\n    if(frame->SIZE < 126)\n    {\n        byte = frame->SIZE;\n        w(&byte,1,arg); //transmit size\n    }\n    else if(frame->SIZE <  0xFFFF){ //can we fit it into an uint16?\n        byte=126;\n        w(&byte,1,arg); //transmit extended lenght indicator\n\n        //send lower 2 bytes of the uint64 len \n        byte = 0xFF & frame->SIZE >> 8;\n        w(&byte,1,arg);\n\n        byte = 0xFF & frame->SIZE;\n        w(&byte,1,arg);        \n\n    }\n    else{\n        byte=127;\n        w(&byte,1,arg); //transmit extended lenght indicator\n\n        //transmit the whole uint64\n        w((char *)&frame->SIZE,8,arg);\n    }\n\n    //transmit the data\n    w(frame->DATA,frame->SIZE,arg);\n\n}\n\nvoid ICACHE_FLASH_ATTR ws_output_frame(ws_frame *frame,enum ws_frame_type type,char * payload,size_t payloadSize){\n\n    \n    //is FIN?\n    frame->FIN = 1; //we don't support continuation frames, yet\n\n    frame->SIZE = payloadSize;\n\n    frame->TYPE = type;    \n\n    frame->MASKED=0; //server shouldn't mask according to https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17\n\n    frame->DATA = payload;\n\n}\n\nvoid ICACHE_FLASH_ATTR ws_parse_frame(ws_frame *frame,char * data,size_t dataLen){\n\n\n    uint8_t byte = data[0];\n\n    //is FIN?\n    frame->FIN = byte & 0x80;\n\n    //opcode\n    frame->TYPE = byte & 0x0F;\n\n\n    if( (frame->TYPE > 0x03 && frame->TYPE < 0x08) || frame->TYPE > 0x0B )\n    {\n       NODE_DBG(\"\\tInvalid frame type %02X\",frame->TYPE);\n       frame->TYPE=WS_INVALID;\n       return;\n    }\n\n    //mask\n    byte = data[1];\n    frame->MASKED = byte & 0x80;\n\n    //frame size\n    frame->SIZE = byte & 0x7F;\n\n    int offset = 2;\n    if(frame->SIZE == 126)\n    {\n        frame->SIZE=0;\n        frame->SIZE = data[3];                 //LSB\n        frame->SIZE |= (uint64_t)data[2] << 8; //MSB\n        offset=4;\n    }\n    else if(frame->SIZE == 127){\n        frame->SIZE=0;\n        frame->SIZE |= (uint64_t)data[2] << 56; \n        frame->SIZE |= (uint64_t)data[3] << 48; \n        frame->SIZE |= (uint64_t)data[4] << 40; \n        frame->SIZE |= (uint64_t)data[5] << 32; \n        frame->SIZE |= (uint64_t)data[6] << 24; \n        frame->SIZE |= (uint64_t)data[7] << 16; \n        frame->SIZE |= (uint64_t)data[8] <<  8; \n        frame->SIZE |= (uint64_t)data[9] ; \n        offset=10;\n    }\n\n    if(frame->MASKED){\n\n        //read mask key\n        char mask[4];\n        mask[0]=data[offset];\n        mask[1]=data[offset+1];\n        mask[2]=data[offset+2];\n        mask[3]=data[offset+3];\n\n        offset+=4;\n\n        //unmaks data\n        uint64_t i;\n        for(i=0;i<frame->SIZE;i++){\n            data[i+offset] ^= mask[i % 4];                    \n        }\n\n    }\n\n    frame->DATA = &data[offset];\n\n}\n\n\n\nws_frame * ICACHE_FLASH_ATTR ws_make_pong(ws_frame *ping){\n\n    ws_output_frame(ping,WS_PONG,ping->DATA,ping->SIZE);\n\n    return ping;\n}"
  },
  {
    "path": "app/http/websocket.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n #ifndef __WEBSOCKET_H\n #define __WEBSOCKET_H\n\n\n\ntypedef void (*write_function)(const char *data,size_t len,void * arg);  //callback function\n\n\nenum ws_frame_type{\n\n    WS_CONTINUATION=0x00,\n    WS_TEXT=0x01,\n    WS_BINARY=0x02,\n    WS_PING=0x09,\n    WS_PONG=0x0A,\n    WS_CLOSE=0x08,\n    WS_INVALID=0xFF\n};\n\ntypedef struct{\n\n    uint8_t FIN;\n    uint8_t MASKED;\n    enum ws_frame_type TYPE;\n\n    uint64_t SIZE;\n    char * DATA;\n\n} ws_frame;\n\nvoid ICACHE_FLASH_ATTR ws_parse_frame(ws_frame *frame,char * data,size_t dataLen);\nvoid ICACHE_FLASH_ATTR ws_output_frame(ws_frame *frame,enum ws_frame_type type,char * payload,size_t payloadSize);\nvoid ICACHE_FLASH_ATTR ws_write_frame(ws_frame *frame,write_function w,void *arg);\n\n #endif \n\n\n"
  },
  {
    "path": "app/http/ws_app.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n\n#include \"c_types.h\"\n#include \"user_interface.h\"\n#include \"espconn.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"cgi.h\"\n#include \"cgi_wifi.h\"\n#include \"cgi_relay.h\"\n#include \"user_config.h\"\n\n#include \"http.h\"\n#include \"http_process.h\"\n#include \"websocket.h\"\n#include \"http_websocket_server.h\"\n\n#define HTTP_PORT 80\n\n#define WS_APP_STREAM_START \"stream start\"\n#define WS_APP_STREAM_STOP \"stream stop\"\n\nstruct ws_app_context {\n\n\tuint8_t stream_data;\n\tint packet_requested_size;\n\thttp_connection *conn;\n\tuint8_t waiting_sent;\n\tchar * packet;\n\tint packet_size;\n};\n\n\nstatic void ICACHE_FLASH_ATTR ws_app_send_packet(struct ws_app_context *context){\n\n\tNODE_DBG(\"Webscoket app send packet size %d, requested: %d\",context->packet_size,context->packet_requested_size);\n\n\tif( (!context->waiting_sent) && context->stream_data==1){\n\t\t//send packet\n\n\t\tif(context->packet_requested_size != context->packet_size ){\n\t\t\tNODE_DBG(\"Webscoket app changing packet size %p\",context);\n\n\t\t\tif(context->packet!=NULL)\n\t\t\t\tos_free(context->packet); //free previous packet\n\n\t\t\tcontext->packet=NULL;\n\t\t\tcontext->packet_size=0;\n\t\t}\t\n\n\t\tif(context->packet==NULL)\n\t\t{\n\t\t\tNODE_DBG(\"Webscoket allocating packet %p\",context);\n\t\t\tcontext->packet = (char *)os_zalloc(context->packet_requested_size);\n\t\t\tcontext->packet_size=context->packet_requested_size;\n\t\t\t//fill with trash data\n\t\t\tint i;\n\t\t\tfor(i=0; i < context->packet_size;i++)\n\t\t\t\tcontext->packet[i]=i%0xFF;\n\t\t} \n\t\t\n\t\thttp_ws_push_bin(context->conn,context->packet,context->packet_size);\n\t\tcontext->waiting_sent=1;\n\t}\n\n}\n\n\nstatic int  ICACHE_FLASH_ATTR ws_app_msg_sent(http_connection *c){\n\n\tNODE_DBG(\"Webscoket app msg sent %p\",c);\n\n\tstruct ws_app_context *context = (struct ws_app_context*)c->reverse;\n\n\tif(context!=NULL){\n\n\t\tNODE_DBG(\"\\tcontext found %p\",context);\n\n\t\tcontext->waiting_sent=0;\n\n\t\tif(context->stream_data==1){\n\t\t\t//no requet to stop made, send next packet\n\t\t\tws_app_send_packet(context);\n\t\t}\n\n\t}\n\n}\n\nstatic int  ICACHE_FLASH_ATTR ws_app_client_disconnected(http_connection *c){\n\n\tNODE_DBG(\"Webscoket app client disconnected %p\",c);\n\n\t//clean up\n\tstruct ws_app_context *context = (struct ws_app_context*)c->reverse;\n\n\tif(context!=NULL){\n\n\t\tif(context->packet!=NULL)\n\t\t\tos_free(context->packet);\n\t\tcontext->packet=NULL;\n\t}\n\tos_free(context);\t\n\n}\n\nstatic int  ICACHE_FLASH_ATTR ws_app_client_connected(http_connection *c){\n\n\tNODE_DBG(\"Webscoket app client connected %p\",c);\n\t\t\n\t//create config\n\tstruct ws_app_context *context = (struct  ws_app_context*)os_zalloc(sizeof(struct ws_app_context));\n\tcontext->conn=c;\n\tc->reverse = context; //so we may find it on callbacks\n\t\n\tNODE_DBG(\"\\tcontext %p\",context);\n}\n\n\nstatic int  ICACHE_FLASH_ATTR ws_app_msg_received(http_connection *c){\n\n\tNODE_DBG(\"Webscoket app msg received %p\",c);\n\n\tstruct ws_app_context *context = (struct ws_app_context*)c->reverse;\n\n\tws_frame *msg = (ws_frame *)c->cgi.argument;\n\tif(msg==NULL)\n\t\treturn HTTP_WS_CGI_MORE; //just ignore and move on\n\n\tif(msg->SIZE <=0)\n\t\treturn HTTP_WS_CGI_MORE; //just ignore and move on\n\n\tchar * s = msg->DATA;\n\tchar *last = s+msg->SIZE;\n\n\t//make a null terminated string\n\tchar * str = (char *)os_zalloc(msg->SIZE + 1);\n\tos_memcpy(str,s,msg->SIZE);\n\tstr[msg->SIZE]=0;\n\n\tNODE_DBG(\"\\tmsg: %s\",str);\n\t\n\tif(strstr(str,WS_APP_STREAM_START)==str){\n\t\t//request to start stream\n\t\tNODE_DBG(\"\\trequest stream start\");\n\n\t\tchar * s= str + strlen(WS_APP_STREAM_START);\t\t\n\n\t\tint pSize = atoi(s);\n\n\t\tNODE_DBG(\"\\trequest stream packet size %d\",pSize);\n\n\t\tif(pSize>0 && pSize <= 1024)\n\t\t{\t\t\t\t\t\n\t\t\tcontext->packet_requested_size=pSize;\n\t\t\tcontext->stream_data =1;\n\t\t\tif(!context->waiting_sent)\n\t\t\t\tws_app_send_packet(context); //send fisrt pkt\n\t\t}\n\n\t}\n\telse if(strstr(str,WS_APP_STREAM_STOP)==str){\n\t\tNODE_DBG(\"\\trequest stream stop\");\n\t\tcontext->stream_data=0;\n\t}\n\n\tos_free(str);\n\n\treturn HTTP_WS_CGI_MORE;\n\n}\n\nvoid ICACHE_FLASH_ATTR init_ws_server(){\n\n\tNODE_DBG(\"Webscoket app init\");\n\n\t//ws\n\thttp_ws_server_init(ws_app_client_connected,ws_app_client_disconnected,ws_app_msg_received,ws_app_msg_sent);\n\thttp_ws_server_start();\n\n}"
  },
  {
    "path": "app/http/ws_app.h",
    "content": "#ifndef __WS_APP_H\n#define __WS_APP_H\n\n\n\n#endif"
  },
  {
    "path": "app/include/arch/cc.h",
    "content": "/*\n * Copyright (c) 2001, Swedish Institute of Computer Science.\n * All rights reserved. \n *\n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions \n * are met: \n * 1. Redistributions of source code must retain the above copyright \n *    notice, this list of conditions and the following disclaimer. \n * 2. Redistributions in binary form must reproduce the above copyright \n *    notice, this list of conditions and the following disclaimer in the \n *    documentation and/or other materials provided with the distribution. \n * 3. Neither the name of the Institute nor the names of its contributors \n *    may be used to endorse or promote products derived from this software \n *    without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND \n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \n * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE \n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \n * SUCH DAMAGE. \n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __ARCH_CC_H__\n#define __ARCH_CC_H__\n\n//#include <string.h>\n#include \"c_types.h\"\n#include \"ets_sys.h\"\n#include \"osapi.h\"\n#define EFAULT 14\n\n//#define LWIP_PROVIDE_ERRNO\n\n#if (1)\n#define BYTE_ORDER LITTLE_ENDIAN\n#else\n#define BYTE_ORDER BIG_ENDIAN\n#endif\n\n\ntypedef unsigned   char    u8_t;\ntypedef signed     char    s8_t;\ntypedef unsigned   short   u16_t;\ntypedef signed     short   s16_t;\ntypedef unsigned   long    u32_t;\ntypedef signed     long    s32_t;\ntypedef unsigned long   mem_ptr_t;\n\n#define S16_F \"d\"\n#define U16_F \"d\"\n#define X16_F \"x\"\n\n#define S32_F \"d\"\n#define U32_F \"d\"\n#define X32_F \"x\"\n\n\n\n//#define PACK_STRUCT_FIELD(x) x __attribute__((packed))\n#define PACK_STRUCT_FIELD(x) x\n#define PACK_STRUCT_STRUCT __attribute__((packed))\n#define PACK_STRUCT_BEGIN\n#define PACK_STRUCT_END\n\n//#define LWIP_DEBUG\n\n#ifdef LWIP_DEBUG\n#define LWIP_PLATFORM_DIAG(x) os_printf x\n#define LWIP_PLATFORM_ASSERT(x) ETS_ASSERT(x)\n#else\n#define LWIP_PLATFORM_DIAG(x)\n#define LWIP_PLATFORM_ASSERT(x)\n#endif\n\n#define SYS_ARCH_DECL_PROTECT(x)\n#define SYS_ARCH_PROTECT(x)\n#define SYS_ARCH_UNPROTECT(x)\n\n#define LWIP_PLATFORM_BYTESWAP 1\n#define LWIP_PLATFORM_HTONS(_n)  ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff)))\n#define LWIP_PLATFORM_HTONL(_n)  ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8)  & 0xff00) | (((_n) >> 24) & 0xff) ))\n\n#if LWIP_RAW\nextern u8_t memp_memory_RAW_PCB_base[];\n#endif /* LWIP_RAW */\n\n#if LWIP_UDP\nextern u8_t memp_memory_UDP_PCB_base[];\n#endif /* LWIP_UDP */\n\n#if LWIP_TCP\nextern u8_t memp_memory_TCP_PCB_base[];\nextern u8_t memp_memory_TCP_PCB_LISTEN_base[];\nextern u8_t memp_memory_TCP_SEG_base[] SHMEM_ATTR;\n#endif /* LWIP_TCP */\n\n#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */\nextern u8_t memp_memory_SYS_TIMEOUT_base[];\n#endif /* LWIP_TIMERS */\n\nextern u8_t memp_memory_PBUF_base[];\nextern u8_t memp_memory_PBUF_POOL_base[];\n\n\n\n#endif /* __ARCH_CC_H__ */\n"
  },
  {
    "path": "app/include/arch/perf.h",
    "content": "/*\n * Copyright (c) 2001, Swedish Institute of Computer Science.\n * All rights reserved. \n *\n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions \n * are met: \n * 1. Redistributions of source code must retain the above copyright \n *    notice, this list of conditions and the following disclaimer. \n * 2. Redistributions in binary form must reproduce the above copyright \n *    notice, this list of conditions and the following disclaimer in the \n *    documentation and/or other materials provided with the distribution. \n * 3. Neither the name of the Institute nor the names of its contributors \n *    may be used to endorse or promote products derived from this software \n *    without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND \n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \n * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE \n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \n * SUCH DAMAGE. \n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __PERF_H__\n#define __PERF_H__\n\n#define PERF_START    /* null definition */\n#define PERF_STOP(x)  /* null definition */\n\n#endif /* __PERF_H__ */\n"
  },
  {
    "path": "app/include/arch/sys_arch.h",
    "content": ""
  },
  {
    "path": "app/include/driver/gpio16.h",
    "content": "#ifndef __GPIO16_H__\n#define __GPIO16_H__\n\nvoid gpio16_output_conf(void);\nvoid gpio16_output_set(uint8 value);\nvoid gpio16_input_conf(void);\nuint8 gpio16_input_get(void);\n\n#endif\n"
  },
  {
    "path": "app/include/driver/i2c_master.h",
    "content": "#ifndef __I2C_MASTER_H__\n#define __I2C_MASTER_H__\n\n#define I2C_MASTER_SDA_MUX (pin_mux[sda])\n#define I2C_MASTER_SCL_MUX (pin_mux[scl])\n#define I2C_MASTER_SDA_GPIO (pinSDA)\n#define I2C_MASTER_SCL_GPIO (pinSCL)\n#define I2C_MASTER_SDA_FUNC (pin_func[sda])\n#define I2C_MASTER_SCL_FUNC (pin_func[scl])\n\n// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U\n// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTDO_U\n// #define I2C_MASTER_SDA_GPIO 2\n// #define I2C_MASTER_SCL_GPIO 15\n// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2\n// #define I2C_MASTER_SCL_FUNC FUNC_GPIO15\n\n// #define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U\n// #define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_MTMS_U\n// #define I2C_MASTER_SDA_GPIO 2\n// #define I2C_MASTER_SCL_GPIO 14\n// #define I2C_MASTER_SDA_FUNC FUNC_GPIO2\n// #define I2C_MASTER_SCL_FUNC FUNC_GPIO14\n\n//#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO2_U\n//#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO0_U\n//#define I2C_MASTER_SDA_GPIO 2\n//#define I2C_MASTER_SCL_GPIO 0\n//#define I2C_MASTER_SDA_FUNC FUNC_GPIO2\n//#define I2C_MASTER_SCL_FUNC FUNC_GPIO0\n\n#if 0\n#define I2C_MASTER_GPIO_SET(pin)  \\\n    gpio_output_set(1<<pin,0,1<<pin,0)\n\n#define I2C_MASTER_GPIO_CLR(pin) \\\n    gpio_output_set(0,1<<pin,1<<pin,0)\n\n#define I2C_MASTER_GPIO_OUT(pin,val) \\\n    if(val) I2C_MASTER_GPIO_SET(pin);\\\n    else I2C_MASTER_GPIO_CLR(pin)\n#endif\n\n#define I2C_MASTER_SDA_HIGH_SCL_HIGH()  \\\n    gpio_output_set(1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)\n\n#define I2C_MASTER_SDA_HIGH_SCL_LOW()  \\\n    gpio_output_set(1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)\n\n#define I2C_MASTER_SDA_LOW_SCL_HIGH()  \\\n    gpio_output_set(1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)\n\n#define I2C_MASTER_SDA_LOW_SCL_LOW()  \\\n    gpio_output_set(0, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 1<<I2C_MASTER_SDA_GPIO | 1<<I2C_MASTER_SCL_GPIO, 0)\n\nvoid i2c_master_gpio_init(uint8 sda, uint8 scl);\nvoid i2c_master_init(void);\n\n#define i2c_master_wait    os_delay_us\nvoid i2c_master_stop(void);\nvoid i2c_master_start(void);\nvoid i2c_master_setAck(uint8 level);\nuint8 i2c_master_getAck(void);\nuint8 i2c_master_readByte(void);\nvoid i2c_master_writeByte(uint8 wrdata);\n\nbool i2c_master_checkAck(void);\nvoid i2c_master_send_ack(void);\nvoid i2c_master_send_nack(void);\n\nuint8 i2c_master_get_pinSDA();\nuint8 i2c_master_get_pinSCL();\n\n#endif\n"
  },
  {
    "path": "app/include/driver/key.h",
    "content": "#ifndef __KEY_H__\n#define __KEY_H__\n\n#include \"gpio.h\"\n\ntypedef void (* key_function)(void);\n\nstruct single_key_param {\n    uint8 key_level;\n    uint8 gpio_id;\n    uint8 gpio_func;\n    uint32 gpio_name;\n    os_timer_t key_5s;\n    os_timer_t key_50ms;\n    key_function short_press;\n    key_function long_press;\n};\n\nstruct keys_param {\n    uint8 key_num;\n    struct single_key_param **single_key;\n};\n\nstruct single_key_param *key_init_single(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func, key_function long_press, key_function short_press);\nvoid key_init(struct keys_param *key);\n\n#endif\n"
  },
  {
    "path": "app/include/driver/onewire.h",
    "content": "#ifndef __ONEWIRE_H__\n#define __ONEWIRE_H__\n\n#include \"c_types.h\"\n\n// You can exclude certain features from OneWire.  In theory, this\n// might save some space.  In practice, the compiler automatically\n// removes unused code (technically, the linker, using -fdata-sections\n// and -ffunction-sections when compiling, and Wl,--gc-sections\n// when linking), so most of these will not result in any code size\n// reduction.  Well, unless you try to use the missing features\n// and redesign your program to not need them!  ONEWIRE_CRC8_TABLE\n// is the exception, because it selects a fast but large algorithm\n// or a small but slow algorithm.\n\n// you can exclude onewire_search by defining that to 0\n#ifndef ONEWIRE_SEARCH\n#define ONEWIRE_SEARCH 1\n#endif\n\n// You can exclude CRC checks altogether by defining this to 0\n#ifndef ONEWIRE_CRC\n#define ONEWIRE_CRC 1\n#endif\n\n// Select the table-lookup method of computing the 8-bit CRC\n// by setting this to 1.  The lookup table enlarges code size by\n// about 250 bytes.  It does NOT consume RAM (but did in very\n// old versions of OneWire).  If you disable this, a slower\n// but very compact algorithm is used.\n#ifndef ONEWIRE_CRC8_TABLE\n#define ONEWIRE_CRC8_TABLE 0\n#endif\n\n// You can allow 16-bit CRC checks by defining this to 1\n// (Note that ONEWIRE_CRC must also be 1.)\n#ifndef ONEWIRE_CRC16\n#define ONEWIRE_CRC16 1\n#endif\n\n// Platform specific I/O definitions\n\n#define DIRECT_READ(pin)         (0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[pin])))\n#define DIRECT_MODE_INPUT(pin)   GPIO_DIS_OUTPUT(pin_num[pin])\n#define DIRECT_MODE_OUTPUT(pin)\n#define DIRECT_WRITE_LOW(pin)    (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 0))\n#define DIRECT_WRITE_HIGH(pin)   (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 1))\n\nvoid onewire_init(uint8_t pin);\n\n// Perform a 1-Wire reset cycle. Returns 1 if a device responds\n// with a presence pulse.  Returns 0 if there is no device or the\n// bus is shorted or otherwise held low for more than 250uS\nuint8_t onewire_reset(uint8_t pin);\n\n// Issue a 1-Wire rom select command, you do the reset first.\nvoid onewire_select(uint8_t pin, const uint8_t rom[8]);\n\n// Issue a 1-Wire rom skip command, to address all on bus.\nvoid onewire_skip(uint8_t pin);\n\n// Write a byte. If 'power' is one then the wire is held high at\n// the end for parasitically powered devices. You are responsible\n// for eventually depowering it by calling depower() or doing\n// another read or write.\nvoid onewire_write(uint8_t pin, uint8_t v, uint8_t power);\n\nvoid onewire_write_bytes(uint8_t pin, const uint8_t *buf, uint16_t count, bool power);\n\n// Read a byte.\nuint8_t onewire_read(uint8_t pin);\n\nvoid onewire_read_bytes(uint8_t pin, uint8_t *buf, uint16_t count);\n\n// Write a bit. The bus is always left powered at the end, see\n// note in write() about that.\n// void onewire_write_bit(uint8_t pin, uint8_t v);\n\n// Read a bit.\n// uint8_t onewire_read_bit(uint8_t pin);\n\n// Stop forcing power onto the bus. You only need to do this if\n// you used the 'power' flag to write() or used a write_bit() call\n// and aren't about to do another read or write. You would rather\n// not leave this powered if you don't have to, just in case\n// someone shorts your bus.\nvoid onewire_depower(uint8_t pin);\n\n#if ONEWIRE_SEARCH\n// Clear the search state so that if will start from the beginning again.\nvoid onewire_reset_search(uint8_t pin);\n\n// Setup the search to find the device type 'family_code' on the next call\n// to search(*newAddr) if it is present.\nvoid onewire_target_search(uint8_t pin, uint8_t family_code);\n\n// Look for the next device. Returns 1 if a new address has been\n// returned. A zero might mean that the bus is shorted, there are\n// no devices, or you have already retrieved all of them.  It\n// might be a good idea to check the CRC to make sure you didn't\n// get garbage.  The order is deterministic. You will always get\n// the same devices in the same order.\nuint8_t onewire_search(uint8_t pin, uint8_t *newAddr);\n#endif\n\n#if ONEWIRE_CRC\n// Compute a Dallas Semiconductor 8 bit CRC, these are used in the\n// ROM and scratchpad registers.\nuint8_t onewire_crc8(const uint8_t *addr, uint8_t len);\n\n#if ONEWIRE_CRC16\n// Compute the 1-Wire CRC16 and compare it against the received CRC.\n// Example usage (reading a DS2408):\n//    // Put everything in a buffer so we can compute the CRC easily.\n//    uint8_t buf[13];\n//    buf[0] = 0xF0;    // Read PIO Registers\n//    buf[1] = 0x88;    // LSB address\n//    buf[2] = 0x00;    // MSB address\n//    WriteBytes(net, buf, 3);    // Write 3 cmd bytes\n//    ReadBytes(net, buf+3, 10);  // Read 6 data bytes, 2 0xFF, 2 CRC16\n//    if (!CheckCRC16(buf, 11, &buf[11])) {\n//        // Handle error.\n//    }     \n//          \n// @param input - Array of bytes to checksum.\n// @param len - How many bytes to use.\n// @param inverted_crc - The two CRC16 bytes in the received data.\n//                       This should just point into the received data,\n//                       *not* at a 16-bit integer.\n// @param crc - The crc starting value (optional)\n// @return True, iff the CRC matches.\nbool onewire_check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc);\n\n// Compute a Dallas Semiconductor 16 bit CRC.  This is required to check\n// the integrity of data received from many 1-Wire devices.  Note that the\n// CRC computed here is *not* what you'll get from the 1-Wire network,\n// for two reasons:\n//   1) The CRC is transmitted bitwise inverted.\n//   2) Depending on the endian-ness of your processor, the binary\n//      representation of the two-byte return value may have a different\n//      byte order than the two bytes you get from 1-Wire.\n// @param input - Array of bytes to checksum.\n// @param len - How many bytes to use.\n// @param crc - The crc starting value (optional)\n// @return The CRC16, as defined by Dallas Semiconductor.\nuint16_t onewire_crc16(const uint8_t* input, uint16_t len, uint16_t crc);\n#endif\n#endif\n\n#endif\n"
  },
  {
    "path": "app/include/driver/pwm.h",
    "content": "#ifndef __PWM_H__\n#define __PWM_H__\n\n#define PWM_CHANNEL 6\n\nstruct pwm_single_param {\n\tuint16 gpio_set;\n\tuint16 gpio_clear;\n    uint32 h_time;\n};\n\nstruct pwm_param {\n    uint32 period;\n    uint16 freq;\n    uint16  duty[PWM_CHANNEL];\n};\n\n#define PWM_DEPTH 1023\n#define PWM_FREQ_MAX 1000\n\n#define PWM_1S 1000000\n\n// #define PWM_0_OUT_IO_MUX PERIPHS_IO_MUX_MTMS_U\n// #define PWM_0_OUT_IO_NUM 14\n// #define PWM_0_OUT_IO_FUNC  FUNC_GPIO14\n\n// #define PWM_1_OUT_IO_MUX PERIPHS_IO_MUX_MTDI_U\n// #define PWM_1_OUT_IO_NUM 12\n// #define PWM_1_OUT_IO_FUNC  FUNC_GPIO12\n\n// #define PWM_2_OUT_IO_MUX PERIPHS_IO_MUX_MTCK_U\n// #define PWM_2_OUT_IO_NUM 13\n// #define PWM_2_OUT_IO_FUNC  FUNC_GPIO13\n\nvoid pwm_init(uint16 freq, uint16 *duty);\nvoid pwm_start(void);\n\nvoid pwm_set_duty(uint16 duty, uint8 channel);\nuint16 pwm_get_duty(uint8 channel);\nvoid pwm_set_freq(uint16 freq, uint8 channel);\nuint16 pwm_get_freq(uint8 channel);\nbool pwm_add(uint8 channel);\nbool pwm_delete(uint8 channel);\nbool pwm_exist(uint8 channel);\n#endif\n\n"
  },
  {
    "path": "app/include/driver/relay.h",
    "content": "#ifndef __RELAY_H\n#define __RELAY_H\n\n#define RELAY_COUNT 2\n\ntypedef void (*relay_change_callback)(int relay,int state);  //callback function\n\nvoid ICACHE_FLASH_ATTR relay_register_listener(relay_change_callback f);\nvoid ICACHE_FLASH_ATTR relay_unregister_listener(relay_change_callback f);\n\nint ICACHE_FLASH_ATTR relay_get_state(int relayNumber);\nint ICACHE_FLASH_ATTR relay_set_state(int relayNumber,unsigned state);\nint ICACHE_FLASH_ATTR relay_toggle_state(int relayNumber);\nvoid ICACHE_FLASH_ATTR relay_init();\nint ICACHE_FLASH_ATTR relay_count();\n#endif"
  },
  {
    "path": "app/include/driver/spi.h",
    "content": "#ifndef SPI_APP_H\n#define SPI_APP_H\n\n#include \"spi_register.h\"\n#include \"ets_sys.h\"\n#include \"osapi.h\"\n#include \"uart.h\"\n#include \"os_type.h\"\n\n/*SPI number define*/\n#define SPI \t\t\t0\n#define HSPI\t\t\t1\n\n\n\n//lcd drive function\nvoid spi_lcd_mode_init(uint8 spi_no);\nvoid spi_lcd_9bit_write(uint8 spi_no,uint8 high_bit,uint8 low_8bit);\n\n//spi master init funtion\nvoid spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock);\n//use spi send 8bit data\nvoid spi_mast_byte_write(uint8 spi_no,uint8 *data);\n\n//transmit data to esp8266 slave buffer,which needs 16bit transmission ,\n//first byte is master command 0x04, second byte is master data\nvoid spi_byte_write_espslave(uint8 spi_no,uint8 data);\n//read data from esp8266 slave buffer,which needs 16bit transmission ,\n//first byte is master command 0x06, second byte is to read slave data\nvoid spi_byte_read_espslave(uint8 spi_no,uint8 *data);\n\n //esp8266 slave mode initial\nvoid spi_slave_init(uint8 spi_no);\n  //esp8266 slave isr handle funtion,tiggered when any transmission is finished.\n  //the function is registered in spi_slave_init.\nvoid spi_slave_isr_handler(void *para); \n\n\n//hspi test function, used to test esp8266 spi slave\nvoid hspi_master_readwrite_repeat(void);\n\n\nvoid ICACHE_FLASH_ATTR\n    spi_test_init(void);\n\n\n#endif\n\n"
  },
  {
    "path": "app/include/driver/spi_master.h",
    "content": "#ifndef __SPI_MASTER_H__\n#define __SPI_MASTER_H__\n\n#include \"driver/spi_register.h\"\n\n/*SPI number define*/\n#define SPI         0\n#define HSPI        1\n\nvoid spi_master_init(uint8 spi_no);\nvoid spi_master_9bit_write(uint8 spi_no, uint8 high_bit, uint8 low_8bit);\n\n#endif\n"
  },
  {
    "path": "app/include/driver/spi_register.h",
    "content": "/*\n *  Copyright (c) 2010 - 2011 Espressif System\n *\n */\n\n#ifndef SPI_REGISTER_H_INCLUDED\n#define SPI_REGISTER_H_INCLUDED\n\n#define REG_SPI_BASE(i)  (0x60000200-i*0x100)\n#define SPI_CMD(i)                            (REG_SPI_BASE(i)  + 0x0)\n#define SPI_USR (BIT(18))\n\n#define SPI_ADDR(i)                           (REG_SPI_BASE(i)  + 0x4)\n\n#define SPI_CTRL(i)                           (REG_SPI_BASE(i)  + 0x8)\n#define SPI_WR_BIT_ORDER (BIT(26))\n#define SPI_RD_BIT_ORDER (BIT(25))\n#define SPI_QIO_MODE (BIT(24))\n#define SPI_DIO_MODE (BIT(23))\n#define SPI_QOUT_MODE (BIT(20))\n#define SPI_DOUT_MODE (BIT(14))\n#define SPI_FASTRD_MODE (BIT(13))\n\n\n\n#define SPI_RD_STATUS(i)                         (REG_SPI_BASE(i)  + 0x10)\n\n#define SPI_CTRL2(i)                           (REG_SPI_BASE(i)  + 0x14)\n\n#define SPI_CS_DELAY_NUM 0x0000000F\n#define SPI_CS_DELAY_NUM_S 28\n#define SPI_CS_DELAY_MODE 0x00000003\n#define SPI_CS_DELAY_MODE_S 26\n#define SPI_MOSI_DELAY_NUM 0x00000007\n#define SPI_MOSI_DELAY_NUM_S 23\n#define SPI_MOSI_DELAY_MODE 0x00000003\n#define SPI_MOSI_DELAY_MODE_S 21\n#define SPI_MISO_DELAY_NUM 0x00000007\n#define SPI_MISO_DELAY_NUM_S 18\n#define SPI_MISO_DELAY_MODE 0x00000003\n#define SPI_MISO_DELAY_MODE_S 16\n#define SPI_CK_OUT_HIGH_MODE 0x0000000F\n#define SPI_CK_OUT_HIGH_MODE_S 12\n#define SPI_CK_OUT_LOW_MODE 0x0000000F\n#define SPI_CK_OUT_LOW_MODE_S 8\n\n#define SPI_CLOCK(i)                          (REG_SPI_BASE(i)  + 0x18)\n#define SPI_CLK_EQU_SYSCLK (BIT(31))\n#define SPI_CLKDIV_PRE 0x00001FFF\n#define SPI_CLKDIV_PRE_S 18\n#define SPI_CLKCNT_N 0x0000003F\n#define SPI_CLKCNT_N_S 12\n#define SPI_CLKCNT_H 0x0000003F\n#define SPI_CLKCNT_H_S 6\n#define SPI_CLKCNT_L 0x0000003F\n#define SPI_CLKCNT_L_S 0\n\n#define SPI_USER(i)                           (REG_SPI_BASE(i)  + 0x1C)\n#define SPI_USR_COMMAND (BIT(31))\n#define SPI_USR_ADDR (BIT(30))\n#define SPI_USR_DUMMY (BIT(29))\n#define SPI_USR_MISO (BIT(28))\n#define SPI_USR_MOSI (BIT(27))\n\n#define SPI_USR_MOSI_HIGHPART (BIT(25))\n#define SPI_USR_MISO_HIGHPART (BIT(24))\n\n\n#define SPI_SIO (BIT(16))\n#define SPI_FWRITE_QIO (BIT(15))\n#define SPI_FWRITE_DIO (BIT(14))\n#define SPI_FWRITE_QUAD (BIT(13))\n#define SPI_FWRITE_DUAL (BIT(12))\n#define SPI_WR_BYTE_ORDER (BIT(11))\n#define SPI_RD_BYTE_ORDER (BIT(10))\n#define SPI_CK_OUT_EDGE (BIT(7))\n#define SPI_CK_I_EDGE (BIT(6))\n#define SPI_CS_SETUP (BIT(5))\n#define SPI_CS_HOLD (BIT(4))\n#define SPI_FLASH_MODE (BIT(2))\n#define SPI_DOUTDIN (BIT(0))\n\n#define SPI_USER1(i)                          (REG_SPI_BASE(i) + 0x20)\n#define SPI_USR_ADDR_BITLEN 0x0000003F\n#define SPI_USR_ADDR_BITLEN_S 26\n#define SPI_USR_MOSI_BITLEN 0x000001FF\n#define SPI_USR_MOSI_BITLEN_S 17\n#define SPI_USR_MISO_BITLEN 0x000001FF\n#define SPI_USR_MISO_BITLEN_S 8\n\n#define SPI_USR_DUMMY_CYCLELEN 0x000000FF\n#define SPI_USR_DUMMY_CYCLELEN_S 0\n\n#define SPI_USER2(i)                          (REG_SPI_BASE(i)  + 0x24)\n#define SPI_USR_COMMAND_BITLEN 0x0000000F\n#define SPI_USR_COMMAND_BITLEN_S 28\n#define SPI_USR_COMMAND_VALUE 0x0000FFFF\n#define SPI_USR_COMMAND_VALUE_S 0\n\n#define SPI_WR_STATUS(i)                          (REG_SPI_BASE(i)  + 0x28)\n#define SPI_PIN(i)                            (REG_SPI_BASE(i)  + 0x2C)\n#define SPI_CS2_DIS (BIT(2))\n#define SPI_CS1_DIS (BIT(1))\n#define SPI_CS0_DIS (BIT(0))\n\n#define SPI_SLAVE(i)                          (REG_SPI_BASE(i)  + 0x30)\n#define SPI_SYNC_RESET (BIT(31))\n#define SPI_SLAVE_MODE (BIT(30))\n#define SPI_SLV_WR_RD_BUF_EN (BIT(29))\n#define SPI_SLV_WR_RD_STA_EN (BIT(28))\n#define SPI_SLV_CMD_DEFINE (BIT(27))\n#define SPI_TRANS_CNT 0x0000000F\n#define SPI_TRANS_CNT_S 23\n#define SPI_TRANS_DONE_EN (BIT(9))\n#define SPI_SLV_WR_STA_DONE_EN (BIT(8))\n#define SPI_SLV_RD_STA_DONE_EN (BIT(7))\n#define SPI_SLV_WR_BUF_DONE_EN (BIT(6))\n#define SPI_SLV_RD_BUF_DONE_EN (BIT(5))\n\n\n\n#define SLV_SPI_INT_EN   0x0000001f\n#define SLV_SPI_INT_EN_S 5\n\n#define SPI_TRANS_DONE (BIT(4))\n#define SPI_SLV_WR_STA_DONE (BIT(3))\n#define SPI_SLV_RD_STA_DONE (BIT(2))\n#define SPI_SLV_WR_BUF_DONE (BIT(1))\n#define SPI_SLV_RD_BUF_DONE (BIT(0))\n\n#define SPI_SLAVE1(i)                         (REG_SPI_BASE(i)  + 0x34)\n#define SPI_SLV_STATUS_BITLEN 0x0000001F\n#define SPI_SLV_STATUS_BITLEN_S 27\n#define SPI_SLV_BUF_BITLEN 0x000001FF\n#define SPI_SLV_BUF_BITLEN_S 16\n#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F\n#define SPI_SLV_RD_ADDR_BITLEN_S 10\n#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F\n#define SPI_SLV_WR_ADDR_BITLEN_S 4\n\n#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3))\n#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2))\n#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1))\n#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0))\n\n\n\n#define SPI_SLAVE2(i)  (REG_SPI_BASE(i)  + 0x38)\n#define SPI_SLV_WRBUF_DUMMY_CYCLELEN  0X000000FF\n#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24\n#define SPI_SLV_RDBUF_DUMMY_CYCLELEN  0X000000FF\n#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16\n#define SPI_SLV_WRSTR_DUMMY_CYCLELEN  0X000000FF\n#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S  8\n#define SPI_SLV_RDSTR_DUMMY_CYCLELEN  0x000000FF\n#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0\n\n#define SPI_SLAVE3(i)                         (REG_SPI_BASE(i)  + 0x3C)\n#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF\n#define SPI_SLV_WRSTA_CMD_VALUE_S 24\n#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF\n#define SPI_SLV_RDSTA_CMD_VALUE_S 16\n#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF\n#define SPI_SLV_WRBUF_CMD_VALUE_S 8\n#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF\n#define SPI_SLV_RDBUF_CMD_VALUE_S 0\n\n#define SPI_W0(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x40)\n#define SPI_W1(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x44)\n#define SPI_W2(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x48)\n#define SPI_W3(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x4C)\n#define SPI_W4(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x50)\n#define SPI_W5(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x54)\n#define SPI_W6(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x58)\n#define SPI_W7(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x5C)\n#define SPI_W8(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x60)\n#define SPI_W9(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x64)\n#define SPI_W10(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x68)\n#define SPI_W11(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x6C)\n#define SPI_W12(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x70)\n#define SPI_W13(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x74)\n#define SPI_W14(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x78)\n#define SPI_W15(i) \t\t\t\t\t\t\t(REG_SPI_BASE(i) +0x7C)\n\n#define SPI_EXT3(i)                           (REG_SPI_BASE(i)  + 0xFC)\n#define SPI_INT_HOLD_ENA 0x00000003\n#define SPI_INT_HOLD_ENA_S 0\n#endif // SPI_REGISTER_H_INCLUDED\n"
  },
  {
    "path": "app/include/driver/uart.h",
    "content": "#ifndef UART_APP_H\n#define UART_APP_H\n\n#include \"uart_register.h\"\n#include \"eagle_soc.h\"\n#include \"c_types.h\"\n\ntypedef void (*uart0_data_received_callback_t)(uint8_t *data,int len);\n\n#define UART0   0\n#define UART1   1\n\n#define UART_HW_RTS   0   //set 1: enable uart hw flow control RTS, PIN MTDO, FOR UART0\n#define UART_HW_CTS  0    //set1: enable uart hw flow contrl CTS , PIN MTCK, FOR UART0\n\n#define RX_BUFF_SIZE    0x100\n#define TX_BUFF_SIZE    100\n\n#define UART_FIFO_LEN  128  //define the tx fifo length\n#define UART_TX_EMPTY_THRESH_VAL 0x10\n\ntypedef enum {\n    FIVE_BITS = 0x0,\n    SIX_BITS = 0x1,\n    SEVEN_BITS = 0x2,\n    EIGHT_BITS = 0x3\n} UartBitsNum4Char;\n\ntypedef enum {\n    ONE_STOP_BIT             = 0,\n    ONE_HALF_STOP_BIT        = BIT2,\n    TWO_STOP_BIT             = BIT2\n} UartStopBitsNum;\n\ntypedef enum {\n    NONE_BITS = 0,\n    ODD_BITS   = 0,\n    EVEN_BITS = BIT4\n} UartParityMode;\n\ntypedef enum {\n    STICK_PARITY_DIS   = 0,\n    STICK_PARITY_EN    = BIT3 | BIT5\n} UartExistParity;\n\ntypedef enum {\n    BIT_RATE_1200     = 1200,\n    BIT_RATE_2400     = 2400,\n    BIT_RATE_4800     = 4800,  \n    BIT_RATE_9600     = 9600,\n    BIT_RATE_19200   = 19200,\n    BIT_RATE_38400   = 38400,\n    BIT_RATE_57600   = 57600,\n    BIT_RATE_74880   = 74880,\n    BIT_RATE_115200 = 115200,\n    BIT_RATE_230400 = 230400,\n    BIT_RATE_460800 = 460800,\n    BIT_RATE_921600 = 921600\n} UartBautRate;\n\ntypedef enum {\n    NONE_CTRL,\n    HARDWARE_CTRL,\n    XON_XOFF_CTRL\n} UartFlowCtrl;\n\ntypedef enum {\n    EMPTY,\n    UNDER_WRITE,\n    WRITE_OVER\n} RcvMsgBuffState;\n\ntypedef struct {\n    uint32     RcvBuffSize;\n    uint8     *pRcvMsgBuff;\n    uint8     *pWritePos;\n    uint8     *pReadPos;\n    uint8      TrigLvl; //JLU: may need to pad\n    RcvMsgBuffState  BuffState;\n} RcvMsgBuff;\n\ntypedef struct {\n    uint32   TrxBuffSize;\n    uint8   *pTrxBuff;\n} TrxMsgBuff;\n\ntypedef enum {\n    BAUD_RATE_DET,\n    WAIT_SYNC_FRM,\n    SRCH_MSG_HEAD,\n    RCV_MSG_BODY,\n    RCV_ESC_CHAR,\n} RcvMsgState;\n\ntypedef struct {\n    UartBautRate \t     baut_rate;\n    UartBitsNum4Char  data_bits;\n    UartExistParity      exist_parity;\n    UartParityMode \t    parity;    // chip size in byte\n    UartStopBitsNum   stop_bits;\n    UartFlowCtrl         flow_ctrl;\n    RcvMsgBuff          rcv_buff;\n    TrxMsgBuff           trx_buff;\n    RcvMsgState        rcv_state;\n    int                      received;\n    int                      buff_uart_no;  //indicate which uart use tx/rx buffer\n} UartDevice;\n\n\nvoid ICACHE_FLASH_ATTR uart_config(uint8_t uart_no);\nvoid uart_init(UartBautRate uart0_br, UartBautRate uart1_br);\nvoid uart_write_string(uint8_t uart,const char *s);\nvoid uart_write(uint8_t uart,uint8_t *data,int len);\nvoid uart_write_char(uint8_t uart,char c);\n\nvoid uart_clear_data_callback();\nvoid uart_register_data_callback(uart0_data_received_callback_t callback);\n#endif\n\n"
  },
  {
    "path": "app/include/driver/uart_register.h",
    "content": "/*\n * File\t: uart_register.h\n * Copyright (C) 2013 - 2016, Espressif Systems\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of version 3 of the GNU General Public License as\n * published by the Free Software Foundation.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License along\n * with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n/*\n *  Copyright (c) 2010 - 2011 Espressif System\n *\n */\n\n#ifndef UART_REGISTER_H_\n#define UART_REGISTER_H_\n\n#define REG_UART_BASE(i)                (0x60000000 + (i)*0xf00)\n//version value:32'h062000\n\n#define UART_FIFO(i)                    (REG_UART_BASE(i) + 0x0)\n#define UART_RXFIFO_RD_BYTE                 0x000000FF\n#define UART_RXFIFO_RD_BYTE_S               0\n\n#define UART_INT_RAW(i)                 (REG_UART_BASE(i) + 0x4)\n#define UART_RXFIFO_TOUT_INT_RAW            (BIT(8))\n#define UART_BRK_DET_INT_RAW                (BIT(7))\n#define UART_CTS_CHG_INT_RAW                (BIT(6))\n#define UART_DSR_CHG_INT_RAW                (BIT(5))\n#define UART_RXFIFO_OVF_INT_RAW             (BIT(4))\n#define UART_FRM_ERR_INT_RAW                (BIT(3))\n#define UART_PARITY_ERR_INT_RAW             (BIT(2))\n#define UART_TXFIFO_EMPTY_INT_RAW           (BIT(1))\n#define UART_RXFIFO_FULL_INT_RAW            (BIT(0))\n\n#define UART_INT_ST(i)                  (REG_UART_BASE(i) + 0x8)\n#define UART_RXFIFO_TOUT_INT_ST             (BIT(8))\n#define UART_BRK_DET_INT_ST                 (BIT(7))\n#define UART_CTS_CHG_INT_ST                 (BIT(6))\n#define UART_DSR_CHG_INT_ST                 (BIT(5))\n#define UART_RXFIFO_OVF_INT_ST              (BIT(4))\n#define UART_FRM_ERR_INT_ST                 (BIT(3))\n#define UART_PARITY_ERR_INT_ST              (BIT(2))\n#define UART_TXFIFO_EMPTY_INT_ST            (BIT(1))\n#define UART_RXFIFO_FULL_INT_ST             (BIT(0))\n\n#define UART_INT_ENA(i)                 (REG_UART_BASE(i) + 0xC)\n#define UART_RXFIFO_TOUT_INT_ENA            (BIT(8))\n#define UART_BRK_DET_INT_ENA                (BIT(7))\n#define UART_CTS_CHG_INT_ENA                (BIT(6))\n#define UART_DSR_CHG_INT_ENA                (BIT(5))\n#define UART_RXFIFO_OVF_INT_ENA             (BIT(4))\n#define UART_FRM_ERR_INT_ENA                (BIT(3))\n#define UART_PARITY_ERR_INT_ENA             (BIT(2))\n#define UART_TXFIFO_EMPTY_INT_ENA           (BIT(1))\n#define UART_RXFIFO_FULL_INT_ENA            (BIT(0))\n\n#define UART_INT_CLR(i)                 (REG_UART_BASE(i) + 0x10)\n#define UART_RXFIFO_TOUT_INT_CLR            (BIT(8))\n#define UART_BRK_DET_INT_CLR                (BIT(7))\n#define UART_CTS_CHG_INT_CLR                (BIT(6))\n#define UART_DSR_CHG_INT_CLR                (BIT(5))\n#define UART_RXFIFO_OVF_INT_CLR             (BIT(4))\n#define UART_FRM_ERR_INT_CLR                (BIT(3))\n#define UART_PARITY_ERR_INT_CLR             (BIT(2))\n#define UART_TXFIFO_EMPTY_INT_CLR           (BIT(1))\n#define UART_RXFIFO_FULL_INT_CLR            (BIT(0))\n\n#define UART_CLKDIV(i)                  (REG_UART_BASE(i) + 0x14)\n#define UART_CLKDIV_CNT                     0x000FFFFF\n#define UART_CLKDIV_S                       0\n\n#define UART_AUTOBAUD(i)                (REG_UART_BASE(i) + 0x18)\n#define UART_GLITCH_FILT                    0x000000FF\n#define UART_GLITCH_FILT_S                  8\n#define UART_AUTOBAUD_EN                    (BIT(0))\n\n#define UART_STATUS(i)                  (REG_UART_BASE(i) + 0x1C)\n#define UART_TXD                            (BIT(31))\n#define UART_RTSN                           (BIT(30))\n#define UART_DTRN                           (BIT(29))\n#define UART_TXFIFO_CNT                     0x000000FF\n#define UART_TXFIFO_CNT_S                   16\n#define UART_RXD                            (BIT(15))\n#define UART_CTSN                           (BIT(14))\n#define UART_DSRN                           (BIT(13))\n#define UART_RXFIFO_CNT                     0x000000FF\n#define UART_RXFIFO_CNT_S                   0\n\n#define UART_CONF0(i)                   (REG_UART_BASE(i) + 0x20)\n#define UART_DTR_INV                        (BIT(24))\n#define UART_RTS_INV                        (BIT(23))\n#define UART_TXD_INV                        (BIT(22))\n#define UART_DSR_INV                        (BIT(21))\n#define UART_CTS_INV                        (BIT(20))\n#define UART_RXD_INV                        (BIT(19))\n#define UART_TXFIFO_RST                     (BIT(18))\n#define UART_RXFIFO_RST                     (BIT(17))\n#define UART_IRDA_EN                        (BIT(16))\n#define UART_TX_FLOW_EN                     (BIT(15))\n#define UART_LOOPBACK                       (BIT(14))\n#define UART_IRDA_RX_INV                    (BIT(13))\n#define UART_IRDA_TX_INV                    (BIT(12))\n#define UART_IRDA_WCTL                      (BIT(11))\n#define UART_IRDA_TX_EN                     (BIT(10))\n#define UART_IRDA_DPLX                      (BIT(9))\n#define UART_TXD_BRK                        (BIT(8))\n#define UART_SW_DTR                         (BIT(7))\n#define UART_SW_RTS                         (BIT(6))\n#define UART_STOP_BIT_NUM                   0x00000003\n#define UART_STOP_BIT_NUM_S                 4\n#define UART_BIT_NUM                        0x00000003\n#define UART_BIT_NUM_S                      2\n#define UART_PARITY_EN                      (BIT(1))\n#define UART_PARITY_EN_M                0x00000001\n#define UART_PARITY_EN_S                 1\n#define UART_PARITY                         (BIT(0))\n#define UART_PARITY_M                       0x00000001\n#define UART_PARITY_S                        0\n\n#define UART_CONF1(i)                   (REG_UART_BASE(i) + 0x24)\n#define UART_RX_TOUT_EN                     (BIT(31))\n#define UART_RX_TOUT_THRHD                  0x0000007F\n#define UART_RX_TOUT_THRHD_S                24\n#define UART_RX_FLOW_EN                     (BIT(23))\n#define UART_RX_FLOW_THRHD                  0x0000007F\n#define UART_RX_FLOW_THRHD_S                16\n#define UART_TXFIFO_EMPTY_THRHD             0x0000007F\n#define UART_TXFIFO_EMPTY_THRHD_S           8\n#define UART_RXFIFO_FULL_THRHD              0x0000007F\n#define UART_RXFIFO_FULL_THRHD_S            0\n\n#define UART_LOWPULSE(i)                (REG_UART_BASE(i) + 0x28)\n#define UART_LOWPULSE_MIN_CNT               0x000FFFFF\n#define UART_LOWPULSE_MIN_CNT_S             0\n\n#define UART_HIGHPULSE(i)               (REG_UART_BASE(i) + 0x2C)\n#define UART_HIGHPULSE_MIN_CNT              0x000FFFFF\n#define UART_HIGHPULSE_MIN_CNT_S            0\n\n#define UART_PULSE_NUM(i)               (REG_UART_BASE(i) + 0x30)\n#define UART_PULSE_NUM_CNT                  0x0003FF\n#define UART_PULSE_NUM_CNT_S                0\n\n#define UART_DATE(i)                    (REG_UART_BASE(i) + 0x78)\n#define UART_ID(i)                      (REG_UART_BASE(i) + 0x7C)\n\n#endif // UART_REGISTER_H_INCLUDED\n\n"
  },
  {
    "path": "app/include/json/cJson.h",
    "content": "/*\n  Copyright (c) 2009 Dave Gamble\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to deal\n  in the Software without restriction, including without limitation the rights\n  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  THE SOFTWARE.\n*/\n\n#ifndef cJSON__h\n#define cJSON__h\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n/* cJSON Types: */\n#define cJSON_False 0\n#define cJSON_True 1\n#define cJSON_NULL 2\n#define cJSON_Number 3\n#define cJSON_String 4\n#define cJSON_Array 5\n#define cJSON_Object 6\n\n#define cJSON_IsReference 256\n\n/* The cJSON structure: */\ntypedef struct cJSON {\n    struct cJSON *next, *prev;  /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */\n    struct cJSON *child;        /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */\n\n    int type;                   /* The type of the item, as above. */\n\n    char *valuestring;          /* The item's string, if type==cJSON_String */\n    int valueint;               /* The item's number, if type==cJSON_Number */\n    double valuedouble;         /* The item's number, if type==cJSON_Number */\n\n    char *string;               /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */\n} cJSON;\n\n/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */\ncJSON *cJSON_Parse(const char *value);\n/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */\nchar  *cJSON_Print(cJSON *item);\n/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */\nchar  *cJSON_PrintUnformatted(cJSON *item);\n/* Delete a cJSON entity and all subentities. */\nvoid   cJSON_Delete(cJSON *c);\n\n/* Returns the number of items in an array (or object). */\nint    cJSON_GetArraySize(cJSON *array);\n/* Retrieve item number \"item\" from array \"array\". Returns NULL if unsuccessful. */\ncJSON *cJSON_GetArrayItem(cJSON *array, int item);\n/* Get item \"string\" from object. Case insensitive. */\ncJSON *cJSON_GetObjectItem(cJSON *object, const char *string);\n\n/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */\nconst char *cJSON_GetErrorPtr(void);\n\n/* These calls create a cJSON item of the appropriate type. */\ncJSON *cJSON_CreateNull(void);\ncJSON *cJSON_CreateTrue(void);\ncJSON *cJSON_CreateFalse(void);\ncJSON *cJSON_CreateBool(int b);\ncJSON *cJSON_CreateNumber(double num);\ncJSON *cJSON_CreateString(const char *string);\ncJSON *cJSON_CreateArray(void);\ncJSON *cJSON_CreateObject(void);\n\n/* These utilities create an Array of count items. */\ncJSON *cJSON_CreateIntArray(const int *numbers, int count);\ncJSON *cJSON_CreateFloatArray(const float *numbers, int count);\ncJSON *cJSON_CreateDoubleArray(const double *numbers, int count);\ncJSON *cJSON_CreateStringArray(const char **strings, int count);\n\n/* Append item to the specified array/object. */\nvoid cJSON_AddItemToArray(cJSON *array, cJSON *item);\nvoid cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);\n/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */\nvoid cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);\nvoid cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);\n\n/* Remove/Detatch items from Arrays/Objects. */\ncJSON *cJSON_DetachItemFromArray(cJSON *array, int which);\nvoid   cJSON_DeleteItemFromArray(cJSON *array, int which);\ncJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);\nvoid   cJSON_DeleteItemFromObject(cJSON *object, const char *string);\n\n/* Update array items. */\nvoid cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);\nvoid cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);\n\n/* Duplicate a cJSON item */\ncJSON *cJSON_Duplicate(cJSON *item, int recurse);\n/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will\nneed to be released. With recurse!=0, it will duplicate any children connected to the item.\nThe item->next and ->prev pointers are always zero on return from Duplicate. */\n\n/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */\ncJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);\n\nvoid cJSON_Minify(char *json);\n\n/* Macros for creating things quickly. */\n#define cJSON_AddNullToObject(object,name)      cJSON_AddItemToObject(object, name, cJSON_CreateNull())\n#define cJSON_AddTrueToObject(object,name)      cJSON_AddItemToObject(object, name, cJSON_CreateTrue())\n#define cJSON_AddFalseToObject(object,name)     cJSON_AddItemToObject(object, name, cJSON_CreateFalse())\n#define cJSON_AddBoolToObject(object,name,b)    cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))\n#define cJSON_AddNumberToObject(object,name,n)  cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))\n#define cJSON_AddStringToObject(object,name,s)  cJSON_AddItemToObject(object, name, cJSON_CreateString(s))\n\n/* When assigning an integer value, it needs to be propagated to valuedouble too. */\n#define cJSON_SetIntValue(object,val)           ((object)?(object)->valueint=(object)->valuedouble=(val):(val))\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "app/include/lwip/api.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_API_H__\n#define __LWIP_API_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\n\n#include <stddef.h> /* for size_t */\n\n#include \"lwip/netbuf.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Throughout this file, IP addresses and port numbers are expected to be in\n * the same byte order as in the corresponding pcb.\n */\n\n/* Flags for netconn_write (u8_t) */\n#define NETCONN_NOFLAG    0x00\n#define NETCONN_NOCOPY    0x00 /* Only for source code compatibility */\n#define NETCONN_COPY      0x01\n#define NETCONN_MORE      0x02\n#define NETCONN_DONTBLOCK 0x04\n\n/* Flags for struct netconn.flags (u8_t) */\n/** TCP: when data passed to netconn_write doesn't fit into the send buffer,\n    this temporarily stores whether to wake up the original application task\n    if data couldn't be sent in the first try. */\n#define NETCONN_FLAG_WRITE_DELAYED            0x01\n/** Should this netconn avoid blocking? */\n#define NETCONN_FLAG_NON_BLOCKING             0x02\n/** Was the last connect action a non-blocking one? */\n#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT   0x04\n/** If this is set, a TCP netconn must call netconn_recved() to update\n    the TCP receive window (done automatically if not set). */\n#define NETCONN_FLAG_NO_AUTO_RECVED           0x08\n/** If a nonblocking write has been rejected before, poll_tcp needs to\n    check if the netconn is writable again */\n#define NETCONN_FLAG_CHECK_WRITESPACE         0x10\n\n\n/* Helpers to process several netconn_types by the same code */\n#define NETCONNTYPE_GROUP(t)    (t&0xF0)\n#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)\n\n/** Protocol family and type of the netconn */\nenum netconn_type {\n  NETCONN_INVALID    = 0,\n  /* NETCONN_TCP Group */\n  NETCONN_TCP        = 0x10,\n  /* NETCONN_UDP Group */\n  NETCONN_UDP        = 0x20,\n  NETCONN_UDPLITE    = 0x21,\n  NETCONN_UDPNOCHKSUM= 0x22,\n  /* NETCONN_RAW Group */\n  NETCONN_RAW        = 0x40\n};\n\n/** Current state of the netconn. Non-TCP netconns are always\n * in state NETCONN_NONE! */\nenum netconn_state {\n  NETCONN_NONE,\n  NETCONN_WRITE,\n  NETCONN_LISTEN,\n  NETCONN_CONNECT,\n  NETCONN_CLOSE\n};\n\n/** Use to inform the callback function about changes */\nenum netconn_evt {\n  NETCONN_EVT_RCVPLUS,\n  NETCONN_EVT_RCVMINUS,\n  NETCONN_EVT_SENDPLUS,\n  NETCONN_EVT_SENDMINUS,\n  NETCONN_EVT_ERROR\n};\n\n#if LWIP_IGMP\n/** Used for netconn_join_leave_group() */\nenum netconn_igmp {\n  NETCONN_JOIN,\n  NETCONN_LEAVE\n};\n#endif /* LWIP_IGMP */\n\n/* forward-declare some structs to avoid to include their headers */\nstruct ip_pcb;\nstruct tcp_pcb;\nstruct udp_pcb;\nstruct raw_pcb;\nstruct netconn;\nstruct api_msg_msg;\n\n/** A callback prototype to inform about events for a netconn */\ntypedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);\n\n/** A netconn descriptor */\nstruct netconn {\n  /** type of the netconn (TCP, UDP or RAW) */\n  enum netconn_type type;\n  /** current state of the netconn */\n  enum netconn_state state;\n  /** the lwIP internal protocol control block */\n  union {\n    struct ip_pcb  *ip;\n    struct tcp_pcb *tcp;\n    struct udp_pcb *udp;\n    struct raw_pcb *raw;\n  } pcb;\n  /** the last error this netconn had */\n  err_t last_err;\n  /** sem that is used to synchroneously execute functions in the core context */\n  sys_sem_t op_completed;\n  /** mbox where received packets are stored until they are fetched\n      by the netconn application thread (can grow quite big) */\n  sys_mbox_t recvmbox;\n#if LWIP_TCP\n  /** mbox where new connections are stored until processed\n      by the application thread */\n  sys_mbox_t acceptmbox;\n#endif /* LWIP_TCP */\n  /** only used for socket layer */\n#if LWIP_SOCKET\n  int socket;\n#endif /* LWIP_SOCKET */\n#if LWIP_SO_RCVTIMEO\n  /** timeout to wait for new data to be received\n      (or connections to arrive for listening netconns) */\n  int recv_timeout;\n#endif /* LWIP_SO_RCVTIMEO */\n#if LWIP_SO_RCVBUF\n  /** maximum amount of bytes queued in recvmbox\n      not used for TCP: adjust TCP_WND instead! */\n  int recv_bufsize;\n  /** number of bytes currently in recvmbox to be received,\n      tested against recv_bufsize to limit bytes on recvmbox\n      for UDP and RAW, used for FIONREAD */\n  s16_t recv_avail;\n#endif /* LWIP_SO_RCVBUF */\n  /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */\n  u8_t flags;\n#if LWIP_TCP\n  /** TCP: when data passed to netconn_write doesn't fit into the send buffer,\n      this temporarily stores how much is already sent. */\n  size_t write_offset;\n  /** TCP: when data passed to netconn_write doesn't fit into the send buffer,\n      this temporarily stores the message.\n      Also used during connect and close. */\n  struct api_msg_msg *current_msg;\n#endif /* LWIP_TCP */\n  /** A callback function that is informed about events for this netconn */\n  netconn_callback callback;\n};\n\n/** Register an Network connection event */\n#define API_EVENT(c,e,l) if (c->callback) {         \\\n                           (*c->callback)(c, e, l); \\\n                         }\n\n/** Set conn->last_err to err but don't overwrite fatal errors */\n#define NETCONN_SET_SAFE_ERR(conn, err) do { \\\n  SYS_ARCH_DECL_PROTECT(lev); \\\n  SYS_ARCH_PROTECT(lev); \\\n  if (!ERR_IS_FATAL((conn)->last_err)) { \\\n    (conn)->last_err = err; \\\n  } \\\n  SYS_ARCH_UNPROTECT(lev); \\\n} while(0);\n\n/* Network connection functions: */\n#define netconn_new(t)                  netconn_new_with_proto_and_callback(t, 0, NULL)\n#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)\nstruct\nnetconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,\n                                             netconn_callback callback);\nerr_t   netconn_delete(struct netconn *conn);\n/** Get the type of a netconn (as enum netconn_type). */\n#define netconn_type(conn) (conn->type)\n\nerr_t   netconn_getaddr(struct netconn *conn, ip_addr_t *addr,\n                        u16_t *port, u8_t local);\n#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)\n#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)\n\nerr_t   netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port);\nerr_t   netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port);\nerr_t   netconn_disconnect (struct netconn *conn);\nerr_t   netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);\n#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)\nerr_t   netconn_accept(struct netconn *conn, struct netconn **new_conn);\nerr_t   netconn_recv(struct netconn *conn, struct netbuf **new_buf);\nerr_t   netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf);\nvoid    netconn_recved(struct netconn *conn, u32_t length);\nerr_t   netconn_sendto(struct netconn *conn, struct netbuf *buf,\n                       ip_addr_t *addr, u16_t port);\nerr_t   netconn_send(struct netconn *conn, struct netbuf *buf);\nerr_t   netconn_write(struct netconn *conn, const void *dataptr, size_t size,\n                      u8_t apiflags);\nerr_t   netconn_close(struct netconn *conn);\nerr_t   netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);\n\n#if LWIP_IGMP\nerr_t   netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,\n                                 ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);\n#endif /* LWIP_IGMP */\n#if LWIP_DNS\nerr_t   netconn_gethostbyname(const char *name, ip_addr_t *addr);\n#endif /* LWIP_DNS */\n\n#define netconn_err(conn)               ((conn)->last_err)\n#define netconn_recv_bufsize(conn)      ((conn)->recv_bufsize)\n\n/** Set the blocking status of netconn calls (@todo: write/send is missing) */\n#define netconn_set_nonblocking(conn, val)  do { if(val) { \\\n  (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \\\n} else { \\\n  (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)\n/** Get the blocking status of netconn calls (@todo: write/send is missing) */\n#define netconn_is_nonblocking(conn)        (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)\n\n/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */\n#define netconn_set_noautorecved(conn, val)  do { if(val) { \\\n  (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \\\n} else { \\\n  (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0)\n/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */\n#define netconn_get_noautorecved(conn)        (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)\n\n#if LWIP_SO_RCVTIMEO\n/** Set the receive timeout in milliseconds */\n#define netconn_set_recvtimeout(conn, timeout)      ((conn)->recv_timeout = (timeout))\n/** Get the receive timeout in milliseconds */\n#define netconn_get_recvtimeout(conn)               ((conn)->recv_timeout)\n#endif /* LWIP_SO_RCVTIMEO */\n#if LWIP_SO_RCVBUF\n/** Set the receive buffer in bytes */\n#define netconn_set_recvbufsize(conn, recvbufsize)  ((conn)->recv_bufsize = (recvbufsize))\n/** Get the receive buffer in bytes */\n#define netconn_get_recvbufsize(conn)               ((conn)->recv_bufsize)\n#endif /* LWIP_SO_RCVBUF*/\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_NETCONN */\n\n#endif /* __LWIP_API_H__ */\n"
  },
  {
    "path": "app/include/lwip/api_msg.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_API_MSG_H__\n#define __LWIP_API_MSG_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\n\n#include <stddef.h> /* for size_t */\n\n#include \"lwip/ip_addr.h\"\n#include \"lwip/err.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/igmp.h\"\n#include \"lwip/api.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* For the netconn API, these values are use as a bitmask! */\n#define NETCONN_SHUT_RD   1\n#define NETCONN_SHUT_WR   2\n#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)\n\n/* IP addresses and port numbers are expected to be in\n * the same byte order as in the corresponding pcb.\n */\n/** This struct includes everything that is necessary to execute a function\n    for a netconn in another thread context (mainly used to process netconns\n    in the tcpip_thread context to be thread safe). */\nstruct api_msg_msg {\n  /** The netconn which to process - always needed: it includes the semaphore\n      which is used to block the application thread until the function finished. */\n  struct netconn *conn;\n  /** The return value of the function executed in tcpip_thread. */\n  err_t err;\n  /** Depending on the executed function, one of these union members is used */\n  union {\n    /** used for do_send */\n    struct netbuf *b;\n    /** used for do_newconn */\n    struct {\n      u8_t proto;\n    } n;\n    /** used for do_bind and do_connect */\n    struct {\n      ip_addr_t *ipaddr;\n      u16_t port;\n    } bc;\n    /** used for do_getaddr */\n    struct {\n      ip_addr_t *ipaddr;\n      u16_t *port;\n      u8_t local;\n    } ad;\n    /** used for do_write */\n    struct {\n      const void *dataptr;\n      size_t len;\n      u8_t apiflags;\n    } w;\n    /** used for do_recv */\n    struct {\n      u32_t len;\n    } r;\n    /** used for do_close (/shutdown) */\n    struct {\n      u8_t shut;\n    } sd;\n#if LWIP_IGMP\n    /** used for do_join_leave_group */\n    struct {\n      ip_addr_t *multiaddr;\n      ip_addr_t *netif_addr;\n      enum netconn_igmp join_or_leave;\n    } jl;\n#endif /* LWIP_IGMP */\n#if TCP_LISTEN_BACKLOG\n    struct {\n      u8_t backlog;\n    } lb;\n#endif /* TCP_LISTEN_BACKLOG */\n  } msg;\n};\n\n/** This struct contains a function to execute in another thread context and\n    a struct api_msg_msg that serves as an argument for this function.\n    This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */\nstruct api_msg {\n  /** function to execute in tcpip_thread context */\n  void (* function)(struct api_msg_msg *msg);\n  /** arguments for this function */\n  struct api_msg_msg msg;\n};\n\n#if LWIP_DNS\n/** As do_gethostbyname requires more arguments but doesn't require a netconn,\n    it has its own struct (to avoid struct api_msg getting bigger than necessary).\n    do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg\n    (see netconn_gethostbyname). */\nstruct dns_api_msg {\n  /** Hostname to query or dotted IP address string */\n  const char *name;\n  /** Rhe resolved address is stored here */\n  ip_addr_t *addr;\n  /** This semaphore is posted when the name is resolved, the application thread\n      should wait on it. */\n  sys_sem_t *sem;\n  /** Errors are given back here */\n  err_t *err;\n};\n#endif /* LWIP_DNS */\n\nvoid do_newconn         ( struct api_msg_msg *msg);\nvoid do_delconn         ( struct api_msg_msg *msg);\nvoid do_bind            ( struct api_msg_msg *msg);\nvoid do_connect         ( struct api_msg_msg *msg);\nvoid do_disconnect      ( struct api_msg_msg *msg);\nvoid do_listen          ( struct api_msg_msg *msg);\nvoid do_send            ( struct api_msg_msg *msg);\nvoid do_recv            ( struct api_msg_msg *msg);\nvoid do_write           ( struct api_msg_msg *msg);\nvoid do_getaddr         ( struct api_msg_msg *msg);\nvoid do_close           ( struct api_msg_msg *msg);\nvoid do_shutdown        ( struct api_msg_msg *msg);\n#if LWIP_IGMP\nvoid do_join_leave_group( struct api_msg_msg *msg);\n#endif /* LWIP_IGMP */\n\n#if LWIP_DNS\nvoid do_gethostbyname(void *arg);\n#endif /* LWIP_DNS */\n\nstruct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);\nvoid netconn_free(struct netconn *conn);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_NETCONN */\n\n#endif /* __LWIP_API_MSG_H__ */\n"
  },
  {
    "path": "app/include/lwip/app/dhcpserver.h",
    "content": "#ifndef __DHCPS_H__\r\n#define __DHCPS_H__\r\n\r\n#define USE_DNS\r\n\r\ntypedef struct dhcps_state{\r\n        sint16_t state;\r\n} dhcps_state;\r\n\r\n// ����dhcpclient�Զ����һ��DHCP msg�ṹ��\r\ntypedef struct dhcps_msg {\r\n        uint8_t op, htype, hlen, hops;\r\n        uint8_t xid[4];\r\n        uint16_t secs, flags;\r\n        uint8_t ciaddr[4];\r\n        uint8_t yiaddr[4];\r\n        uint8_t siaddr[4];\r\n        uint8_t giaddr[4];\r\n        uint8_t chaddr[16];\r\n        uint8_t sname[64];\r\n        uint8_t file[128];\r\n        uint8_t options[312];\r\n}dhcps_msg;\r\n\r\n#ifndef LWIP_OPEN_SRC\r\nstruct dhcps_lease {\r\n\tbool enable;\r\n\tstruct ip_addr start_ip;\r\n\tstruct ip_addr end_ip;\r\n};\r\n\r\nenum dhcps_offer_option{\r\n\tOFFER_START = 0x00,\r\n\tOFFER_ROUTER = 0x01,\r\n\tOFFER_END\r\n};\r\n#endif\r\n\r\nstruct dhcps_pool{\r\n\tstruct ip_addr ip;\r\n\tuint8 mac[6];\r\n\tuint32 lease_timer;\r\n};\r\n\r\ntypedef struct _list_node{\r\n\tvoid *pnode;\r\n\tstruct _list_node *pnext;\r\n}list_node;\r\n\r\nextern uint32 dhcps_lease_time;\r\n#define DHCPS_LEASE_TIMER  dhcps_lease_time  //0x05A0\r\n#define DHCPS_MAX_LEASE 0x64\r\n#define BOOTP_BROADCAST 0x8000\r\n\r\n#define DHCP_REQUEST        1\r\n#define DHCP_REPLY          2\r\n#define DHCP_HTYPE_ETHERNET 1\r\n#define DHCP_HLEN_ETHERNET  6\r\n#define DHCP_MSG_LEN      236\r\n\r\n#define DHCPS_SERVER_PORT  67\r\n#define DHCPS_CLIENT_PORT  68\r\n\r\n#define DHCPDISCOVER  1\r\n#define DHCPOFFER     2\r\n#define DHCPREQUEST   3\r\n#define DHCPDECLINE   4\r\n#define DHCPACK       5\r\n#define DHCPNAK       6\r\n#define DHCPRELEASE   7\r\n\r\n#define DHCP_OPTION_SUBNET_MASK   1\r\n#define DHCP_OPTION_ROUTER        3\r\n#define DHCP_OPTION_DNS_SERVER    6\r\n#define DHCP_OPTION_REQ_IPADDR   50\r\n#define DHCP_OPTION_LEASE_TIME   51\r\n#define DHCP_OPTION_MSG_TYPE     53\r\n#define DHCP_OPTION_SERVER_ID    54\r\n#define DHCP_OPTION_INTERFACE_MTU 26\r\n#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31\r\n#define DHCP_OPTION_BROADCAST_ADDRESS 28\r\n#define DHCP_OPTION_REQ_LIST     55\r\n#define DHCP_OPTION_END         255\r\n\r\n//#define USE_CLASS_B_NET 1\r\n#define DHCPS_DEBUG          0\r\n#define MAX_STATION_NUM      8\r\n\r\n#define DHCPS_STATE_OFFER 1\r\n#define DHCPS_STATE_DECLINE 2\r\n#define DHCPS_STATE_ACK 3\r\n#define DHCPS_STATE_NAK 4\r\n#define DHCPS_STATE_IDLE 5\r\n#define DHCPS_STATE_RELEASE 6\r\n\r\n#define   dhcps_router_enabled(offer)\t((offer & OFFER_ROUTER) != 0)\r\n\r\nvoid dhcps_start(struct ip_info *info);\r\nvoid dhcps_stop(void);\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "app/include/lwip/app/espconn.h",
    "content": "#ifndef __ESPCONN_H__\n#define __ESPCONN_H__\n\n#include \"lwip/dns.h\"\n#include \"os_type.h\"\n\n#if 0\n#define espconn_printf(fmt, args...) os_printf(fmt,## args)\n#else \n#define espconn_printf(fmt, args...)\n#endif\n\n\ntypedef void *espconn_handle;\ntypedef void (* espconn_connect_callback)(void *arg);\ntypedef void (* espconn_reconnect_callback)(void *arg, sint8 err);\n\n/* Definitions for error constants. */\n\n#define ESPCONN_OK          0    /* No error, everything OK. */\n#define ESPCONN_MEM        -1    /* Out of memory error.     */\n#define ESPCONN_TIMEOUT    -3    /* Timeout.                 */\n#define ESPCONN_RTE        -4    /* Routing problem.         */\n#define ESPCONN_INPROGRESS  -5   /* Operation in progress    */\n#define ESPCONN_MAXNUM\t\t-7\t /* Total number exceeds the set maximum*/\n\n#define ESPCONN_ABRT       -8    /* Connection aborted.      */\n#define ESPCONN_RST        -9    /* Connection reset.        */\n#define ESPCONN_CLSD       -10   /* Connection closed.       */\n#define ESPCONN_CONN       -11   /* Not connected.           */\n\n#define ESPCONN_ARG        -12   /* Illegal argument.        */\n#define ESPCONN_IF\t\t   -14\t /* Low_level error\t\t\t */\n#define ESPCONN_ISCONN     -15   /* Already connected.       */\n\n#define ESPCONN_HANDSHAKE  -28   /* ssl handshake failed\t */\n#define ESPCONN_RESP_TIMEOUT -29 /* ssl handshake no response*/\n#define ESPCONN_PROTO_MSG  -61   /* ssl application invalid\t */\n\n#define ESPCONN_SSL\t\t\t0x01\n#define ESPCONN_NORM\t\t0x00\n\n#define ESPCONN_STA\t\t\t0x01\n#define ESPCONN_AP\t\t\t0x02\n#define ESPCONN_AP_STA\t\t0x03\n\n#define STA_NETIF      0x00\n#define AP_NETIF       0x01\n\n/** Protocol family and type of the espconn */\nenum espconn_type {\n    ESPCONN_INVALID    = 0,\n    /* ESPCONN_TCP Group */\n    ESPCONN_TCP        = 0x10,\n    /* ESPCONN_UDP Group */\n    ESPCONN_UDP        = 0x20,\n};\n\n/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */\nenum espconn_state {\n    ESPCONN_NONE,\n    ESPCONN_WAIT,\n    ESPCONN_LISTEN,\n    ESPCONN_CONNECT,\n    ESPCONN_WRITE,\n    ESPCONN_READ,\n    ESPCONN_CLOSE\n};\n\ntypedef struct _esp_tcp {\n    int remote_port;\n    int local_port;\n    uint8 local_ip[4];\n    uint8 remote_ip[4];\n\tespconn_connect_callback connect_callback;\n\tespconn_reconnect_callback reconnect_callback;\n\tespconn_connect_callback disconnect_callback;\n\tespconn_connect_callback write_finish_fn;\n} esp_tcp;\n\ntypedef struct _esp_udp {\n    int remote_port;\n    int local_port;\n    uint8 local_ip[4];\n\tuint8 remote_ip[4];\n} esp_udp;\n\ntypedef struct _remot_info{\n\tenum espconn_state state;\n\tint remote_port;\n\tuint8 remote_ip[4];\n}remot_info;\n\n/** A callback prototype to inform about events for a espconn */\ntypedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len);\ntypedef void (* espconn_sent_callback)(void *arg);\n\n/** A espconn descriptor */\nstruct espconn {\n    /** type of the espconn (TCP, UDP) */\n    enum espconn_type type;\n    /** current state of the espconn */\n    enum espconn_state state;\n    union {\n        esp_tcp *tcp;\n        esp_udp *udp;\n    } proto;\n    /** A callback function that is informed about events for this espconn */\n    espconn_recv_callback recv_callback;\n\tespconn_sent_callback sent_callback;\n\tuint8 link_cnt;\n\tvoid *reverse;\n};\n\nenum espconn_option{\n\tESPCONN_START = 0x00,\n\tESPCONN_REUSEADDR = 0x01,\n\tESPCONN_NODELAY = 0x02,\n\tESPCONN_COPY = 0x04,\n\tESPCONN_KEEPALIVE = 0x08,\n\tESPCONN_END\n};\n\nenum espconn_level{\n\tESPCONN_KEEPIDLE,\n\tESPCONN_KEEPINTVL,\n\tESPCONN_KEEPCNT\n};\n\nstruct espconn_packet{\n\tuint16 sent_length;\t\t/* sent length successful*/\n\tuint16 snd_buf_size;\t/* Available buffer size for sending  */\n\tuint16 snd_queuelen;\t/* Available buffer space for sending */\n\tuint16 total_queuelen;\t/* total Available buffer space for sending */\n\tuint32 packseqno;\t\t/* seqno to be sent */\n\tuint32 packseq_nxt;\t\t/* seqno expected */\n\tuint32 packnum;\n};\n\ntypedef struct _espconn_buf{\n\tuint8 *payload;\n\tuint8 *punsent;\n\tuint16 unsent;\n\tuint16 len;\n\tuint16 tot_len;\n\tstruct _espconn_buf *pnext;\n} espconn_buf;\n\ntypedef struct _comon_pkt{\n\tvoid *pcb;\n\tint remote_port;\n\tuint8 remote_ip[4];\n\tuint32 local_port;\n\tuint32 local_ip;\n\tespconn_buf *pbuf;\n\tespconn_buf *ptail;\n\tuint8* ptrbuf;\n\tuint16 cntr;\n\tsint8  err;\n\tuint32 timeout;\n\tuint32 recv_check;\n\tuint8  pbuf_num;\n\tstruct espconn_packet packet_info;\n\tbool write_flag;\n\tenum espconn_option espconn_opt;\n}comon_pkt;\n\ntypedef struct _espconn_msg{\n\tstruct espconn *pespconn;\n\tcomon_pkt pcommon;\n\tuint8 count_opt;\n\tsint16_t hs_status;\t//the status of the handshake\n\tvoid *preverse;\n\tvoid *pssl;\n\tstruct _espconn_msg *pnext;\n\n//***********Code for WIFI_BLOCK from upper**************\n\tuint8 recv_hold_flag;\n\tuint16 recv_holded_buf_Len;\n}espconn_msg;\n\n#ifndef _MDNS_INFO\n#define _MDNS_INFO\nstruct mdns_info {\n\tchar *host_name;\n\tchar *server_name;\n\tuint16 server_port;\n\tunsigned long ipAddr;\n\tchar *txt_data[10];\n};\n#endif\n\n#define linkMax 15\n\n#define   espconn_delay_disabled(espconn)  (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) != 0)\n#define   espconn_delay_enabled(espconn)  (((espconn)->pcommon.espconn_opt & ESPCONN_NODELAY) == 0)\n#define   espconn_reuse_disabled(espconn)  (((espconn)->pcommon.espconn_opt & ESPCONN_REUSEADDR) != 0)\n#define   espconn_copy_disabled(espconn)  (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) != 0)\n#define   espconn_copy_enabled(espconn)  (((espconn)->pcommon.espconn_opt & ESPCONN_COPY) == 0)\n#define   espconn_keepalive_disabled(espconn)  (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) != 0)\n#define   espconn_keepalive_enabled(espconn)  (((espconn)->pcommon.espconn_opt & ESPCONN_KEEPALIVE) == 0)\n\n#define espconn_TaskPrio        26\n#define espconn_TaskQueueLen    15\n\nenum espconn_sig {\n    SIG_ESPCONN_NONE,\n    SIG_ESPCONN_ERRER,\n    SIG_ESPCONN_LISTEN,\n    SIG_ESPCONN_CONNECT,\n    SIG_ESPCONN_WRITE,\n    SIG_ESPCONN_SEND,\n    SIG_ESPCONN_READ,\n    SIG_ESPCONN_CLOSE\n};\n\n/******************************************************************************\n * FunctionName : espconn_copy_partial\n * Description  : reconnect with host\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\n\nvoid espconn_copy_partial(struct espconn *pesp_dest, struct espconn *pesp_source);\n\n/******************************************************************************\n * FunctionName : espconn_copy_partial\n * Description  : insert the node to the active connection list\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\n\nvoid espconn_list_creat(espconn_msg **phead, espconn_msg* pinsert);\n\n/******************************************************************************\n * FunctionName : espconn_list_delete\n * Description  : remove the node from the active connection list\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\n\nvoid espconn_list_delete(espconn_msg **phead, espconn_msg* pdelete);\n\n/******************************************************************************\n * FunctionName : espconn_find_connection\n * Description  : Initialize the server: set up a listening PCB and bind it to\n *                the defined port\n * Parameters   : espconn -- the espconn used to build server\n * Returns      : none\n *******************************************************************************/\n\nbool espconn_find_connection(struct espconn *pespconn, espconn_msg **pnode);\n\n/******************************************************************************\n * FunctionName : espconn_get_connection_info\n * Description  : used to specify the function that should be called when disconnect\n * Parameters   : espconn -- espconn to set the err callback\n *                discon_cb -- err callback function to call when err\n * Returns      : none\n*******************************************************************************/\n\nsint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags);\n\n/******************************************************************************\n * FunctionName : espconn_get_packet_info\n * Description  : get the packet info with host\n * Parameters   : espconn -- the espconn used to disconnect the connection\n * \t\t\t\t  infoarg -- the packet info\n * Returns      : the errur code\n*******************************************************************************/\n\nsint8 espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg);\n\n/******************************************************************************\n * FunctionName : espconn_connect\n * Description  : The function given as the connect\n * Parameters   : espconn -- the espconn used to listen the connection\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_connect(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_disconnect\n * Description  : disconnect with host\n * Parameters   : espconn -- the espconn used to disconnect the connection\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_disconnect(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_delete\n * Description  : disconnect with host\n * Parameters   : espconn -- the espconn used to disconnect the connection\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_delete(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_accept\n * Description  : The function given as the listen\n * Parameters   : espconn -- the espconn used to listen the connection\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_accept(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_create\n * Description  : sent data for client or server\n * Parameters   : espconn -- espconn to the data transmission\n * Returns      : result\n*******************************************************************************/\n\nextern sint8 espconn_create(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_wnd\n * Description  : get the window size of simulatenously active TCP connections\n * Parameters   : none\n * Returns      : the number of TCP_MSS active TCP connections\n*******************************************************************************/\nextern uint8 espconn_tcp_get_wnd(void);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_con\n * Description  : set the window size simulatenously active TCP connections\n * Parameters   : num -- the number of TCP_MSS\n * Returns      : ESPCONN_ARG -- Illegal argument\n * \t\t\t\t  ESPCONN_OK  -- No error\n*******************************************************************************/\nextern sint8 espconn_tcp_set_wnd(uint8 num);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_max_con\n * Description  : get the number of simulatenously active TCP connections\n * Parameters   : none\n * Returns      : none\n*******************************************************************************/\n\nextern uint8 espconn_tcp_get_max_con(void);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_con\n * Description  : set the number of simulatenously active TCP connections\n * Parameters   : num -- total number\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_tcp_set_max_con(uint8 num);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_max_retran\n * Description  : get the Maximum number of retransmissions of data active TCP connections\n * Parameters   : none\n * Returns      : the Maximum number of retransmissions\n*******************************************************************************/\nextern uint8 espconn_tcp_get_max_retran(void);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_retran\n * Description  : set the Maximum number of retransmissions of data active TCP connections\n * Parameters   : num -- the Maximum number of retransmissions\n * Returns      : result\n*******************************************************************************/\n\nextern sint8 espconn_tcp_set_max_retran(uint8 num);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_max_syn\n * Description  : get the Maximum number of retransmissions of SYN segments\n * Parameters   : none\n * Returns      : the Maximum number of retransmissions\n*******************************************************************************/\n\nextern uint8 espconn_tcp_get_max_syn(void);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_syn\n * Description  : set the Maximum number of retransmissions of SYN segments\n * Parameters   : num -- the Maximum number of retransmissions\n * Returns      : result\n*******************************************************************************/\n\nextern sint8 espconn_tcp_set_max_syn(uint8 num);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_max_con_allow\n * Description  : get the count of simulatenously active connections on the server\n * Parameters   : espconn -- espconn to get the count\n * Returns      : result\n*******************************************************************************/\n\nextern sint8 espconn_tcp_get_max_con_allow(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_con_allow\n * Description  : set the count of simulatenously active connections on the server\n * Parameters   : espconn -- espconn to set the count\n * Returns      : result\n*******************************************************************************/\n\nextern sint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num);\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_buf_count\n * Description  : set the total number of espconn_buf on the unsent lists\n * Parameters   : espconn -- espconn to set the count\n * \t\t\t\t  num -- the total number of espconn_buf\n * Returns      : result\n*******************************************************************************/\n\nextern sint8 espconn_tcp_set_buf_count(struct espconn *espconn, uint8 num);\n\n/******************************************************************************\n * FunctionName : espconn_regist_time\n * Description  : used to specify the time that should be called when don't recv data\n * Parameters   : espconn -- the espconn used to the connection\n * \t\t\t\t  interval -- the timer when don't recv data\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag);\n\n/******************************************************************************\n * FunctionName : espconn_regist_sentcb\n * Description  : Used to specify the function that should be called when data\n * \t\t\t\t  has been successfully delivered to the remote host.\n * Parameters   : struct espconn *espconn -- espconn to set the sent callback\n * \t\t\t\t  espconn_sent_callback sent_cb -- sent callback function to \n * \t\t\t\t  call for this espconn when data is successfully sent\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb);\n\n/******************************************************************************\n * FunctionName : espconn_regist_sentcb\n * Description  : Used to specify the function that should be called when data\n *                has been successfully delivered to the remote host.\n * Parameters   : espconn -- espconn to set the sent callback\n *                sent_cb -- sent callback function to call for this espconn\n *                when data is successfully sent\n * Returns      : none\n*******************************************************************************/\nextern sint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn);\n\n/******************************************************************************\n * FunctionName : espconn_sent\n * Description  : sent data for client or server\n * Parameters   : espconn -- espconn to set for client or server\n * \t\t\t\t  psent -- data to send\n *                length -- length of data to send\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length);\n\n/******************************************************************************\n * FunctionName : espconn_regist_connectcb\n * Description  : used to specify the function that should be called when \n * \t\t\t\t  connects to host. \n * Parameters   : espconn -- espconn to set the connect callback \n * \t\t\t\t  connect_cb -- connected callback function to call when connected \n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb);\n\n/******************************************************************************\n * FunctionName : espconn_regist_recvcb\n * Description  : used to specify the function that should be called when recv \n * \t\t\t\t  data from host.\n * Parameters   : espconn -- espconn to set the recv callback \n * \t\t\t\t  recv_cb -- recv callback function to call when recv data\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb);\n\n/******************************************************************************\n * FunctionName : espconn_regist_reconcb\n * Description  : used to specify the function that should be called when connection \n * \t\t\t\t  because of err disconnect.\n * Parameters   : espconn -- espconn to set the err callback \n * \t\t\t\t  recon_cb -- err callback function to call when err \n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb);\n\n/******************************************************************************\n * FunctionName : espconn_regist_disconcb\n * Description  : used to specify the function that should be called when disconnect\n * Parameters   : espconn -- espconn to set the err callback\n *                discon_cb -- err callback function to call when err\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb);\n\n/******************************************************************************\n * FunctionName : espconn_port\n * Description  : access port value for client so that we don't end up bouncing\n *                all connections at the same time .\n * Parameters   : none\n * Returns      : access port value\n*******************************************************************************/\n\nextern uint32 espconn_port(void);\n\n/******************************************************************************\n * FunctionName : espconn_set_opt\n * Description  : access port value for client so that we don't end up bouncing\n *                all connections at the same time .\n * Parameters   : none\n * Returns      : access port value\n*******************************************************************************/\nextern sint8 espconn_set_opt(struct espconn *espconn, uint8 opt);\n\n/******************************************************************************\n * FunctionName : espconn_set_keepalive\n * Description  : access level value for connection so that we set the value for\n * \t\t\t\t  keep alive\n * Parameters   : espconn -- the espconn used to set the connection\n * \t\t\t\t  level -- the connection's level\n * \t\t\t\t  value -- the value of time(s)\n * Returns      : access port value\n*******************************************************************************/\nextern sint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg);\n\n/******************************************************************************\n * FunctionName : espconn_get_keepalive\n * Description  : access level value for connection so that we get the value for\n * \t\t\t\t  keep alive\n * Parameters   : espconn -- the espconn used to get the connection\n * \t\t\t\t  level -- the connection's level\n * Returns      : access keep alive value\n*******************************************************************************/\nextern sint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg);\n\n/******************************************************************************\n * FunctionName : espconn_gethostbyname\n * Description  : Resolve a hostname (string) into an IP address.\n * Parameters   : pespconn -- espconn to resolve a hostname\n *                hostname -- the hostname that is to be queried\n *                addr -- pointer to a ip_addr_t where to store the address if \n *                        it is already cached in the dns_table (only valid if\n *                        ESPCONN_OK is returned!)\n *                found -- a callback function to be called on success, failure\n *                         or timeout (only if ERR_INPROGRESS is returned!)\n * Returns      : err_t return code\n *                - ESPCONN_OK if hostname is a valid IP address string or the host\n *                  name is already in the local names table.\n *                - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server\n *                  for resolution if no errors are present.\n *                - ESPCONN_ARG: dns client not initialized or invalid hostname\n*******************************************************************************/\n\nextern sint8 espconn_gethostbyname(struct espconn *pespconn, const char *name, ip_addr_t *addr, dns_found_callback found);\n\n/******************************************************************************\n * FunctionName : espconn_igmp_join\n * Description  : join a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nextern sint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip);\n\n/******************************************************************************\n * FunctionName : espconn_igmp_leave\n * Description  : leave a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nextern sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip);\n\n/******************************************************************************\n * FunctionName : espconn_mdns_init\n * Description  : register a device with mdns\n * Parameters   : ipAddr -- the ip address of device\n * \t\t\t\t  hostname -- the hostname of device\n * Returns      : none\n*******************************************************************************/\nextern void espconn_mdns_init(struct mdns_info *info);\n/******************************************************************************\n * FunctionName : espconn_mdns_init\n * Description  : close mdns socket\n * Parameters   : void\n * Returns      : none\n*******************************************************************************/\nextern void espconn_mdns_close(void);\n/******************************************************************************\n * FunctionName : mdns_server_register\n * Description  : register a server and join a multicast group\n * Parameters   : none\n * Returns      : none\n*******************************************************************************/\nextern void espconn_mdns_server_register(void);\n/******************************************************************************\n * FunctionName : mdns_server_register\n * Description  : unregister server and leave multicast group\n * Parameters   : none\n * Returns      : none\n*******************************************************************************/\nextern void espconn_mdns_server_unregister(void);\n/******************************************************************************\n * FunctionName : espconn_mdns_get_servername\n * Description  : get server name\n * Parameters   : none\n * Returns      : server name\n*******************************************************************************/\nextern char* espconn_mdns_get_servername(void);\n/******************************************************************************\n * FunctionName : espconn_mdns_get_servername\n * Description  : set server name\n * Parameters   : server name\n * Returns      : none\n*******************************************************************************/\nextern void espconn_mdns_set_servername(const char *name);\n/******************************************************************************\n * FunctionName : espconn_mdns_set_hostname\n * Description  : set host name\n * Parameters   : host name\n * Returns      : none\n*******************************************************************************/\nextern void espconn_mdns_set_hostname(char *name);\n/******************************************************************************\n * FunctionName : espconn_mdns_init\n * Description  : get host name\n * Parameters   : void\n * Returns      : hostname\n*******************************************************************************/\nextern char* espconn_mdns_get_hostname(void);\n/******************************************************************************\n * FunctionName : espconn_mdns_disable\n * Description  : join a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nextern void espconn_mdns_disable(void);\n/******************************************************************************\n * FunctionName : espconn_mdns_enable\n * Description  : enable mdns\n * Parameters   : void\n * Returns      : none\n*******************************************************************************/\nextern void espconn_mdns_enable(void);\n/******************************************************************************\n * FunctionName : espconn_dns_setserver\n * Description  : Initialize one of the DNS servers.\n * Parameters   : numdns -- the index of the DNS server to set must\n * \t\t\t\t  be < DNS_MAX_SERVERS = 2\n * \t\t\t      dnsserver -- IP address of the DNS server to set\n *  Returns     : none\n*******************************************************************************/\nextern void espconn_dns_setserver(u8_t numdns, ip_addr_t *dnsserver);\n#endif\n\n"
  },
  {
    "path": "app/include/lwip/app/espconn_tcp.h",
    "content": "#ifndef __ESPCONN_TCP_H__\r\n#define __ESPCONN_TCP_H__\r\n\r\n#ifndef ESPCONN_TCP_DEBUG\r\n#define ESPCONN_TCP_DEBUG LWIP_DBG_OFF\r\n#endif\r\n#include \"lwip/app/espconn.h\"\r\n\r\n#ifndef ESPCONN_TCP_TIMER\r\n#define ESPCONN_TCP_TIMER 40\r\n#endif\r\n\r\n#define  espconn_keepalive_enable(pcb)   ((pcb)->so_options |= SOF_KEEPALIVE)\r\n#define  espconn_keepalive_disable(pcb)   ((pcb)->so_options &= ~SOF_KEEPALIVE)\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_kill_oldest_pcb\r\n * Description  : A oldest incoming connection has been killed.\r\n * Parameters   : none\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nextern void espconn_kill_oldest_pcb(void);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_tcp_disconnect\r\n * Description  : A new incoming connection has been disconnected.\r\n * Parameters   : espconn -- the espconn used to disconnect with host\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nextern void espconn_tcp_disconnect(espconn_msg *pdiscon);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_tcp_client\r\n * Description  : Initialize the client: set up a connect PCB and bind it to \r\n *                the defined port\r\n * Parameters   : espconn -- the espconn used to build client\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nextern sint8 espconn_tcp_client(struct espconn* espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_tcp_server\r\n * Description  : Initialize the server: set up a listening PCB and bind it to \r\n *                the defined port\r\n * Parameters   : espconn -- the espconn used to build server\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nextern sint8 espconn_tcp_server(struct espconn *espconn);\r\n\r\n#endif /* __CLIENT_TCP_H__ */\r\n\r\n"
  },
  {
    "path": "app/include/lwip/app/espconn_udp.h",
    "content": "#ifndef __ESPCONN_UDP_H__\r\n#define __ESPCONN_UDP_H__\r\n\r\n#ifndef ESPCONN_UDP_DEBUG\r\n#define ESPCONN_UDP_DEBUG LWIP_DBG_OFF\r\n#endif\r\n\r\n#include \"lwip/app/espconn.h\"\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_client\r\n * Description  : Initialize the client: set up a PCB and bind it to the port\r\n * Parameters   : pespconn -- the espconn used to build client\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nextern sint8 espconn_udp_client(struct espconn *pespconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_disconnect\r\n * Description  : A new incoming connection has been disconnected.\r\n * Parameters   : espconn -- the espconn used to disconnect with host\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nextern void espconn_udp_disconnect(espconn_msg *pdiscon);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_server\r\n * Description  : Initialize the server: set up a PCB and bind it to the port\r\n * Parameters   : pespconn -- the espconn used to build server\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nextern sint8 espconn_udp_server(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_sent\r\n * Description  : sent data for client or server\r\n * Parameters   : void *arg -- client or server to send\r\n *                uint8* psent -- Data to send\r\n *                uint16 length -- Length of data to send\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nextern err_t espconn_udp_sent(void *arg, uint8 *psent, uint16 length);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_sendto\r\n * Description  : sent data for UDP\r\n * Parameters   : void *arg -- UDP to send\r\n * \t\t\t\t  uint8* psent -- Data to send\r\n *                uint16 length -- Length of data to send\r\n * Returns      : return espconn error code.\r\n * - ESPCONN_OK. Successful. No error occured.\r\n * - ESPCONN_MEM. Out of memory.\r\n * - ESPCONN_RTE. Could not find route to destination address.\r\n * - More errors could be returned by lower protocol layers.\r\n*******************************************************************************/\r\nextern err_t espconn_udp_sendto(void *arg, uint8 *psent, uint16 length);\r\n\r\n#endif /* __ESPCONN_UDP_H__ */\r\n\r\n\r\n"
  },
  {
    "path": "app/include/lwip/app/ping.h",
    "content": "#ifndef __PING_H__\n#define __PING_H__\n#include \"lwip/ip_addr.h\"\n#include \"lwip/icmp.h\"\n/**\n * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used\n */\n#ifndef PING_USE_SOCKETS\n#define PING_USE_SOCKETS    LWIP_SOCKET\n#endif\n\n/**\n * PING_DEBUG: Enable debugging for PING.\n */\n#ifndef PING_DEBUG\n#define PING_DEBUG     LWIP_DBG_OFF\n#endif\n\n/** ping receive timeout - in milliseconds */\n#ifndef PING_RCV_TIMEO\n#define PING_RCV_TIMEO 1000\n#endif\n\n/** ping delay - in milliseconds */\n#ifndef PING_COARSE\n#define PING_COARSE     1000\n#endif\n\n/** ping identifier - must fit on a u16_t */\n#ifndef PING_ID\n#define PING_ID        0xAFAF\n#endif\n\n/** ping additional data size to include in the packet */\n#ifndef PING_DATA_SIZE\n#define PING_DATA_SIZE 32\n#endif\n\n/** ping result action - no default action */\n#ifndef PING_RESULT\n#define PING_RESULT(ping_ok)\n#endif\n\n#define DEFAULT_PING_MAX_COUNT 4\n#define PING_TIMEOUT_MS 1000\n\ntypedef void (* ping_recv_function)(void* arg, void *pdata);\ntypedef void (* ping_sent_function)(void* arg, void *pdata);\n\nstruct ping_option{\n\tuint32 count;\n\tuint32 ip;\n\tuint32 coarse_time;\n\tping_recv_function recv_function;\n\tping_sent_function sent_function;\n\tvoid* reverse;\n};\n\nstruct ping_msg{\n\tstruct ping_option *ping_opt;\n\tstruct raw_pcb *ping_pcb;\n\tuint32 ping_start;\n\tuint32 ping_sent;\n\tuint32 timeout_count;\n\tuint32 max_count;\n\tuint32 sent_count;\n\tuint32 coarse_time;\n};\n\nstruct ping_resp{\n\tuint32 total_count;\n\tuint32 resp_time;\n\tuint32 seqno;\n\tuint32 timeout_count;\n\tuint32 bytes;\n\tuint32 total_bytes;\n\tuint32 total_time;\n\tsint8  ping_err;\n};\n\nbool ping_start(struct ping_option *ping_opt);\nbool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv);\nbool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent);\n\n#endif /* __PING_H__ */\n"
  },
  {
    "path": "app/include/lwip/arch.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_ARCH_H__\n#define __LWIP_ARCH_H__\n\n#ifndef LITTLE_ENDIAN\n#define LITTLE_ENDIAN 1234\n#endif\n\n#ifndef BIG_ENDIAN\n#define BIG_ENDIAN 4321\n#endif\n\n#include \"arch/cc.h\"\n\n/** Temporary: define format string for size_t if not defined in cc.h */\n#ifndef SZT_F\n#define SZT_F U32_F\n#endif /* SZT_F */\n/** Temporary upgrade helper: define format string for u8_t as hex if not\n    defined in cc.h */\n#ifndef X8_F\n#define X8_F  \"02x\"\n#endif /* X8_F */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef PACK_STRUCT_BEGIN\n#define PACK_STRUCT_BEGIN\n#endif /* PACK_STRUCT_BEGIN */\n\n#ifndef PACK_STRUCT_END\n#define PACK_STRUCT_END\n#endif /* PACK_STRUCT_END */\n\n#ifndef PACK_STRUCT_FIELD\n#define PACK_STRUCT_FIELD(x) x\n#endif /* PACK_STRUCT_FIELD */\n\n\n#ifndef LWIP_UNUSED_ARG\n#define LWIP_UNUSED_ARG(x) (void)x\n#endif /* LWIP_UNUSED_ARG */ \n\n\n#ifdef LWIP_PROVIDE_ERRNO\n\n#define  EPERM         1  /* Operation not permitted */\n#define  ENOENT        2  /* No such file or directory */\n#define  ESRCH         3  /* No such process */\n#define  EINTR         4  /* Interrupted system call */\n#define  EIO           5  /* I/O error */\n#define  ENXIO         6  /* No such device or address */\n#define  E2BIG         7  /* Arg list too long */\n#define  ENOEXEC       8  /* Exec format error */\n#define  EBADF         9  /* Bad file number */\n#define  ECHILD       10  /* No child processes */\n#define  EAGAIN       11  /* Try again */\n#define  ENOMEM       12  /* Out of memory */\n#define  EACCES       13  /* Permission denied */\n#define  EFAULT       14  /* Bad address */\n#define  ENOTBLK      15  /* Block device required */\n#define  EBUSY        16  /* Device or resource busy */\n#define  EEXIST       17  /* File exists */\n#define  EXDEV        18  /* Cross-device link */\n#define  ENODEV       19  /* No such device */\n#define  ENOTDIR      20  /* Not a directory */\n#define  EISDIR       21  /* Is a directory */\n#define  EINVAL       22  /* Invalid argument */\n#define  ENFILE       23  /* File table overflow */\n#define  EMFILE       24  /* Too many open files */\n#define  ENOTTY       25  /* Not a typewriter */\n#define  ETXTBSY      26  /* Text file busy */\n#define  EFBIG        27  /* File too large */\n#define  ENOSPC       28  /* No space left on device */\n#define  ESPIPE       29  /* Illegal seek */\n#define  EROFS        30  /* Read-only file system */\n#define  EMLINK       31  /* Too many links */\n#define  EPIPE        32  /* Broken pipe */\n#define  EDOM         33  /* Math argument out of domain of func */\n#define  ERANGE       34  /* Math result not representable */\n#define  EDEADLK      35  /* Resource deadlock would occur */\n#define  ENAMETOOLONG 36  /* File name too long */\n#define  ENOLCK       37  /* No record locks available */\n#define  ENOSYS       38  /* Function not implemented */\n#define  ENOTEMPTY    39  /* Directory not empty */\n#define  ELOOP        40  /* Too many symbolic links encountered */\n#define  EWOULDBLOCK  EAGAIN  /* Operation would block */\n#define  ENOMSG       42  /* No message of desired type */\n#define  EIDRM        43  /* Identifier removed */\n#define  ECHRNG       44  /* Channel number out of range */\n#define  EL2NSYNC     45  /* Level 2 not synchronized */\n#define  EL3HLT       46  /* Level 3 halted */\n#define  EL3RST       47  /* Level 3 reset */\n#define  ELNRNG       48  /* Link number out of range */\n#define  EUNATCH      49  /* Protocol driver not attached */\n#define  ENOCSI       50  /* No CSI structure available */\n#define  EL2HLT       51  /* Level 2 halted */\n#define  EBADE        52  /* Invalid exchange */\n#define  EBADR        53  /* Invalid request descriptor */\n#define  EXFULL       54  /* Exchange full */\n#define  ENOANO       55  /* No anode */\n#define  EBADRQC      56  /* Invalid request code */\n#define  EBADSLT      57  /* Invalid slot */\n\n#define  EDEADLOCK    EDEADLK\n\n#define  EBFONT       59  /* Bad font file format */\n#define  ENOSTR       60  /* Device not a stream */\n#define  ENODATA      61  /* No data available */\n#define  ETIME        62  /* Timer expired */\n#define  ENOSR        63  /* Out of streams resources */\n#define  ENONET       64  /* Machine is not on the network */\n#define  ENOPKG       65  /* Package not installed */\n#define  EREMOTE      66  /* Object is remote */\n#define  ENOLINK      67  /* Link has been severed */\n#define  EADV         68  /* Advertise error */\n#define  ESRMNT       69  /* Srmount error */\n#define  ECOMM        70  /* Communication error on send */\n#define  EPROTO       71  /* Protocol error */\n#define  EMULTIHOP    72  /* Multihop attempted */\n#define  EDOTDOT      73  /* RFS specific error */\n#define  EBADMSG      74  /* Not a data message */\n#define  EOVERFLOW    75  /* Value too large for defined data type */\n#define  ENOTUNIQ     76  /* Name not unique on network */\n#define  EBADFD       77  /* File descriptor in bad state */\n#define  EREMCHG      78  /* Remote address changed */\n#define  ELIBACC      79  /* Can not access a needed shared library */\n#define  ELIBBAD      80  /* Accessing a corrupted shared library */\n#define  ELIBSCN      81  /* .lib section in a.out corrupted */\n#define  ELIBMAX      82  /* Attempting to link in too many shared libraries */\n#define  ELIBEXEC     83  /* Cannot exec a shared library directly */\n#define  EILSEQ       84  /* Illegal byte sequence */\n#define  ERESTART     85  /* Interrupted system call should be restarted */\n#define  ESTRPIPE     86  /* Streams pipe error */\n#define  EUSERS       87  /* Too many users */\n#define  ENOTSOCK     88  /* Socket operation on non-socket */\n#define  EDESTADDRREQ 89  /* Destination address required */\n#define  EMSGSIZE     90  /* Message too long */\n#define  EPROTOTYPE   91  /* Protocol wrong type for socket */\n#define  ENOPROTOOPT  92  /* Protocol not available */\n#define  EPROTONOSUPPORT 93  /* Protocol not supported */\n#define  ESOCKTNOSUPPORT 94  /* Socket type not supported */\n#define  EOPNOTSUPP      95  /* Operation not supported on transport endpoint */\n#define  EPFNOSUPPORT    96  /* Protocol family not supported */\n#define  EAFNOSUPPORT    97  /* Address family not supported by protocol */\n#define  EADDRINUSE      98  /* Address already in use */\n#define  EADDRNOTAVAIL   99  /* Cannot assign requested address */\n#define  ENETDOWN       100  /* Network is down */\n#define  ENETUNREACH    101  /* Network is unreachable */\n#define  ENETRESET      102  /* Network dropped connection because of reset */\n#define  ECONNABORTED   103  /* Software caused connection abort */\n#define  ECONNRESET     104  /* Connection reset by peer */\n#define  ENOBUFS        105  /* No buffer space available */\n#define  EISCONN        106  /* Transport endpoint is already connected */\n#define  ENOTCONN       107  /* Transport endpoint is not connected */\n#define  ESHUTDOWN      108  /* Cannot send after transport endpoint shutdown */\n#define  ETOOMANYREFS   109  /* Too many references: cannot splice */\n#define  ETIMEDOUT      110  /* Connection timed out */\n#define  ECONNREFUSED   111  /* Connection refused */\n#define  EHOSTDOWN      112  /* Host is down */\n#define  EHOSTUNREACH   113  /* No route to host */\n#define  EALREADY       114  /* Operation already in progress */\n#define  EINPROGRESS    115  /* Operation now in progress */\n#define  ESTALE         116  /* Stale NFS file handle */\n#define  EUCLEAN        117  /* Structure needs cleaning */\n#define  ENOTNAM        118  /* Not a XENIX named type file */\n#define  ENAVAIL        119  /* No XENIX semaphores available */\n#define  EISNAM         120  /* Is a named type file */\n#define  EREMOTEIO      121  /* Remote I/O error */\n#define  EDQUOT         122  /* Quota exceeded */\n\n#define  ENOMEDIUM      123  /* No medium found */\n#define  EMEDIUMTYPE    124  /* Wrong medium type */\n\n\n#define ENSROK                    0 /* DNS server returned answer with no data */\n#define ENSRNODATA              160 /* DNS server returned answer with no data */\n#define ENSRFORMERR             161 /* DNS server claims query was misformatted */\n#define ENSRSERVFAIL            162 /* DNS server returned general failure */\n#define ENSRNOTFOUND            163 /* Domain name not found */\n#define ENSRNOTIMP              164 /* DNS server does not implement requested operation */\n#define ENSRREFUSED             165 /* DNS server refused query */\n#define ENSRBADQUERY            166 /* Misformatted DNS query */\n#define ENSRBADNAME             167 /* Misformatted domain name */\n#define ENSRBADFAMILY           168 /* Unsupported address family */\n#define ENSRBADRESP             169 /* Misformatted DNS reply */\n#define ENSRCONNREFUSED         170 /* Could not contact DNS servers */\n#define ENSRTIMEOUT             171 /* Timeout while contacting DNS servers */\n#define ENSROF                  172 /* End of file */\n#define ENSRFILE                173 /* Error reading file */\n#define ENSRNOMEM               174 /* Out of memory */\n#define ENSRDESTRUCTION         175 /* Application terminated lookup */\n#define ENSRQUERYDOMAINTOOLONG  176 /* Domain name is too long */\n#define ENSRCNAMELOOP           177 /* Domain name is too long */\n\n#ifndef errno\nextern int errno;\n#endif\n\n#endif /* LWIP_PROVIDE_ERRNO */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_ARCH_H__ */\n"
  },
  {
    "path": "app/include/lwip/autoip.h",
    "content": "/**\n * @file\n *\n * AutoIP Automatic LinkLocal IP Configuration\n */\n\n/*\n *\n * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * Author: Dominik Spies <kontakt@dspies.de>\n *\n * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform\n * with RFC 3927.\n *\n *\n * Please coordinate changes and requests with Dominik Spies\n * <kontakt@dspies.de>\n */\n \n#ifndef __LWIP_AUTOIP_H__\n#define __LWIP_AUTOIP_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/netif.h\"\n#include \"lwip/udp.h\"\n#include \"netif/etharp.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* AutoIP Timing */\n#define AUTOIP_TMR_INTERVAL      100\n#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)\n\n/* RFC 3927 Constants */\n#define PROBE_WAIT               1   /* second   (initial random delay)                 */\n#define PROBE_MIN                1   /* second   (minimum delay till repeated probe)    */\n#define PROBE_MAX                2   /* seconds  (maximum delay till repeated probe)    */\n#define PROBE_NUM                3   /*          (number of probe packets)              */\n#define ANNOUNCE_NUM             2   /*          (number of announcement packets)       */\n#define ANNOUNCE_INTERVAL        2   /* seconds  (time between announcement packets)    */\n#define ANNOUNCE_WAIT            2   /* seconds  (delay before announcing)              */\n#define MAX_CONFLICTS            10  /*          (max conflicts before rate limiting)   */\n#define RATE_LIMIT_INTERVAL      60  /* seconds  (delay between successive attempts)    */\n#define DEFEND_INTERVAL          10  /* seconds  (min. wait between defensive ARPs)     */\n\n/* AutoIP client states */\n#define AUTOIP_STATE_OFF         0\n#define AUTOIP_STATE_PROBING     1\n#define AUTOIP_STATE_ANNOUNCING  2\n#define AUTOIP_STATE_BOUND       3\n\nstruct autoip\n{\n  ip_addr_t llipaddr;       /* the currently selected, probed, announced or used LL IP-Address */\n  u8_t state;               /* current AutoIP state machine state */\n  u8_t sent_num;            /* sent number of probes or announces, dependent on state */\n  u16_t ttw;                /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */\n  u8_t lastconflict;        /* ticks until a conflict can be solved by defending */\n  u8_t tried_llipaddr;      /* total number of probed/used Link Local IP-Addresses */\n};\n\n\n/** Init srand, has to be called before entering mainloop */\nvoid autoip_init(void);\n\n/** Set a struct autoip allocated by the application to work with */\nvoid autoip_set_struct(struct netif *netif, struct autoip *autoip);\n\n/** Start AutoIP client */\nerr_t autoip_start(struct netif *netif);\n\n/** Stop AutoIP client */\nerr_t autoip_stop(struct netif *netif);\n\n/** Handles every incoming ARP Packet, called by etharp_arp_input */\nvoid autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);\n\n/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */\nvoid autoip_tmr(void);\n\n/** Handle a possible change in the network configuration */\nvoid autoip_network_changed(struct netif *netif);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_AUTOIP */\n\n#endif /* __LWIP_AUTOIP_H__ */\n"
  },
  {
    "path": "app/include/lwip/debug.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_DEBUG_H__\n#define __LWIP_DEBUG_H__\n\n#include \"lwip/arch.h\"\n\n/** lower two bits indicate debug level\n * - 0 all\n * - 1 warning\n * - 2 serious\n * - 3 severe\n */\n#define LWIP_DBG_LEVEL_ALL     0x00\n#define LWIP_DBG_LEVEL_OFF     LWIP_DBG_LEVEL_ALL /* compatibility define only */\n#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */\n#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */\n#define LWIP_DBG_LEVEL_SEVERE  0x03\n#define LWIP_DBG_MASK_LEVEL    0x03\n\n/** flag for LWIP_DEBUGF to enable that debug message */\n#define LWIP_DBG_ON            0x80U\n/** flag for LWIP_DEBUGF to disable that debug message */\n#define LWIP_DBG_OFF           0x00U\n\n/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */\n#define LWIP_DBG_TRACE         0x40U\n/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */\n#define LWIP_DBG_STATE         0x20U\n/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */\n#define LWIP_DBG_FRESH         0x10U\n/** flag for LWIP_DEBUGF to halt after printing this debug message */\n#define LWIP_DBG_HALT          0x08U\n\n#ifndef LWIP_NOASSERT\n#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \\\n  LWIP_PLATFORM_ASSERT(message); } while(0)\n#else  /* LWIP_NOASSERT */\n#define LWIP_ASSERT(message, assertion) \n#endif /* LWIP_NOASSERT */\n\n/** if \"expression\" isn't true, then print \"message\" and execute \"handler\" expression */\n#ifndef LWIP_ERROR\n#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \\\n  LWIP_PLATFORM_ASSERT(message); handler;}} while(0)\n#endif /* LWIP_ERROR */\n\n#ifdef LWIP_DEBUG\n/** print debug message only if debug message type is enabled...\n *  AND is of correct type AND is at least LWIP_DBG_LEVEL\n */\n#define LWIP_DEBUGF(debug, message) do { \\\n                               if ( \\\n                                   ((debug) & LWIP_DBG_ON) && \\\n                                   ((debug) & LWIP_DBG_TYPES_ON) && \\\n                                   ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \\\n                                 LWIP_PLATFORM_DIAG(message); \\\n                                 if ((debug) & LWIP_DBG_HALT) { \\\n                                   while(1); \\\n                                 } \\\n                               } \\\n                             } while(0)\n\n#else  /* LWIP_DEBUG */\n#define LWIP_DEBUGF(debug, message) \n#endif /* LWIP_DEBUG */\n\n#endif /* __LWIP_DEBUG_H__ */\n\n"
  },
  {
    "path": "app/include/lwip/def.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_DEF_H__\n#define __LWIP_DEF_H__\n\n/* arch.h might define NULL already */\n#include \"lwip/arch.h\"\n#include \"lwip/opt.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define LWIP_MAX(x , y)  (((x) > (y)) ? (x) : (y))\n#define LWIP_MIN(x , y)  (((x) < (y)) ? (x) : (y))\n\n#ifndef NULL\n#define NULL ((void *)0)\n#endif\n\n/** Get the absolute difference between 2 u32_t values (correcting overflows)\n * 'a' is expected to be 'higher' (without overflow) than 'b'. */\n#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) \n\n/* Endianess-optimized shifting of two u8_t to create one u16_t */\n#if BYTE_ORDER == LITTLE_ENDIAN\n#define LWIP_MAKE_U16(a, b) ((a << 8) | b)\n#else\n#define LWIP_MAKE_U16(a, b) ((b << 8) | a)\n#endif \n\n#ifndef LWIP_PLATFORM_BYTESWAP\n#define LWIP_PLATFORM_BYTESWAP 0\n#endif\n\n#ifndef LWIP_PREFIX_BYTEORDER_FUNCS\n/* workaround for naming collisions on some platforms */\n\n#ifdef htons\n#undef htons\n#endif /* htons */\n#ifdef htonl\n#undef htonl\n#endif /* htonl */\n#ifdef ntohs\n#undef ntohs\n#endif /* ntohs */\n#ifdef ntohl\n#undef ntohl\n#endif /* ntohl */\n\n#define htons(x) lwip_htons(x)\n#define ntohs(x) lwip_ntohs(x)\n#define htonl(x) lwip_htonl(x)\n#define ntohl(x) lwip_ntohl(x)\n#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */\n\n#if BYTE_ORDER == BIG_ENDIAN\n#define lwip_htons(x) (x)\n#define lwip_ntohs(x) (x)\n#define lwip_htonl(x) (x)\n#define lwip_ntohl(x) (x)\n#define PP_HTONS(x) (x)\n#define PP_NTOHS(x) (x)\n#define PP_HTONL(x) (x)\n#define PP_NTOHL(x) (x)\n#else /* BYTE_ORDER != BIG_ENDIAN */\n#if LWIP_PLATFORM_BYTESWAP\n#define lwip_htons(x) LWIP_PLATFORM_HTONS(x)\n#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x)\n#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x)\n#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x)\n#else /* LWIP_PLATFORM_BYTESWAP */\nu16_t lwip_htons(u16_t x);\nu16_t lwip_ntohs(u16_t x);\nu32_t lwip_htonl(u32_t x);\nu32_t lwip_ntohl(u32_t x);\n#endif /* LWIP_PLATFORM_BYTESWAP */\n\n/* These macros should be calculated by the preprocessor and are used\n   with compile-time constants only (so that there is no little-endian\n   overhead at runtime). */\n#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))\n#define PP_NTOHS(x) PP_HTONS(x)\n#define PP_HTONL(x) ((((x) & 0xff) << 24) | \\\n                     (((x) & 0xff00) << 8) | \\\n                     (((x) & 0xff0000UL) >> 8) | \\\n                     (((x) & 0xff000000UL) >> 24))\n#define PP_NTOHL(x) PP_HTONL(x)\n\n#endif /* BYTE_ORDER == BIG_ENDIAN */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_DEF_H__ */\n\n"
  },
  {
    "path": "app/include/lwip/dhcp.h",
    "content": "/** @file\n */\n\n#ifndef __LWIP_DHCP_H__\n#define __LWIP_DHCP_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/netif.h\"\n#include \"lwip/udp.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** period (in seconds) of the application calling dhcp_coarse_tmr() */\n#define DHCP_COARSE_TIMER_SECS 60 \n/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */\n#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL)\n/** period (in milliseconds) of the application calling dhcp_fine_tmr() */\n#define DHCP_FINE_TIMER_MSECS 500 \n\n#define DHCP_CHADDR_LEN 16U\n#define DHCP_SNAME_LEN  64U\n#define DHCP_FILE_LEN   128U\n\nstruct dhcp\n{\n  /** transaction identifier of last sent request */ \n  u32_t xid;\n  /** our connection to the DHCP server */ \n  struct udp_pcb *pcb;\n  /** incoming msg */\n  struct dhcp_msg *msg_in;\n  /** current DHCP state machine state */\n  u8_t state;\n  /** retries of current request */\n  u8_t tries;\n#if LWIP_DHCP_AUTOIP_COOP\n  u8_t autoip_coop_state;\n#endif\n  u8_t subnet_mask_given;\n\n  struct pbuf *p_out; /* pbuf of outcoming msg */\n  struct dhcp_msg *msg_out; /* outgoing msg */\n  u16_t options_out_len; /* outgoing msg options length */\n  u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */\n  u16_t t1_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */\n  u16_t t2_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */\n  ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */\n  ip_addr_t offered_ip_addr;\n  ip_addr_t offered_sn_mask;\n  ip_addr_t offered_gw_addr;\n \n  u32_t offered_t0_lease; /* lease period (in seconds) */\n  u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */\n  u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period)  */\n  /* @todo: LWIP_DHCP_BOOTP_FILE configuration option?\n     integrate with possible TFTP-client for booting? */\n#define LWIP_DHCP_BOOTP_FILE 0\n#if LWIP_DHCP_BOOTP_FILE\n  ip_addr_t offered_si_addr;\n  char boot_file_name[DHCP_FILE_LEN];\n#endif /* LWIP_DHCP_BOOTPFILE */\n};\n\n/* MUST be compiled with \"pack structs\" or equivalent! */\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\n/** minimum set of fields of any DHCP message */\nstruct dhcp_msg\n{\n  PACK_STRUCT_FIELD(u8_t op);\n  PACK_STRUCT_FIELD(u8_t htype);\n  PACK_STRUCT_FIELD(u8_t hlen);\n  PACK_STRUCT_FIELD(u8_t hops);\n  PACK_STRUCT_FIELD(u32_t xid);\n  PACK_STRUCT_FIELD(u16_t secs);\n  PACK_STRUCT_FIELD(u16_t flags);\n  PACK_STRUCT_FIELD(ip_addr_p_t ciaddr);\n  PACK_STRUCT_FIELD(ip_addr_p_t yiaddr);\n  PACK_STRUCT_FIELD(ip_addr_p_t siaddr);\n  PACK_STRUCT_FIELD(ip_addr_p_t giaddr);\n  PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);\n  PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);\n  PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);\n  PACK_STRUCT_FIELD(u32_t cookie);\n#define DHCP_MIN_OPTIONS_LEN 68U\n/** make sure user does not configure this too small */\n#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))\n#  undef DHCP_OPTIONS_LEN\n#endif\n/** allow this to be configured in lwipopts.h, but not too small */\n#if (!defined(DHCP_OPTIONS_LEN))\n/** set this to be sufficient for your options in outgoing DHCP msgs */\n#  define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN\n#endif\n  PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\nvoid dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);\n/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */\n#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)\nvoid dhcp_cleanup(struct netif *netif);\n/** start DHCP configuration */\nerr_t dhcp_start(struct netif *netif);\n/** enforce early lease renewal (not needed normally)*/\nerr_t dhcp_renew(struct netif *netif);\n/** release the DHCP lease, usually called before dhcp_stop()*/\nerr_t dhcp_release(struct netif *netif);\n/** stop DHCP configuration */\nvoid dhcp_stop(struct netif *netif);\n/** inform server of our manual IP address */\nvoid dhcp_inform(struct netif *netif);\n/** Handle a possible change in the network configuration */\nvoid dhcp_network_changed(struct netif *netif);\n\n/** if enabled, check whether the offered IP address is not in use, using ARP */\n#if DHCP_DOES_ARP_CHECK\nvoid dhcp_arp_reply(struct netif *netif, ip_addr_t *addr);\n#endif\n\n/** to be called every minute */\nvoid dhcp_coarse_tmr(void);\n/** to be called every half second */\nvoid dhcp_fine_tmr(void);\n \n/** DHCP message item offsets and length */\n#define DHCP_OP_OFS       0\n#define DHCP_HTYPE_OFS    1\n#define DHCP_HLEN_OFS     2\n#define DHCP_HOPS_OFS     3\n#define DHCP_XID_OFS      4\n#define DHCP_SECS_OFS     8\n#define DHCP_FLAGS_OFS    10\n#define DHCP_CIADDR_OFS   12\n#define DHCP_YIADDR_OFS   16\n#define DHCP_SIADDR_OFS   20\n#define DHCP_GIADDR_OFS   24\n#define DHCP_CHADDR_OFS   28\n#define DHCP_SNAME_OFS    44\n#define DHCP_FILE_OFS     108\n#define DHCP_MSG_LEN      236\n\n#define DHCP_COOKIE_OFS   DHCP_MSG_LEN\n#define DHCP_OPTIONS_OFS  (DHCP_MSG_LEN + 4)\n\n#define DHCP_CLIENT_PORT  68  \n#define DHCP_SERVER_PORT  67\n\n/** DHCP client states */\n#define DHCP_OFF          0\n#define DHCP_REQUESTING   1\n#define DHCP_INIT         2\n#define DHCP_REBOOTING    3\n#define DHCP_REBINDING    4\n#define DHCP_RENEWING     5\n#define DHCP_SELECTING    6\n#define DHCP_INFORMING    7\n#define DHCP_CHECKING     8\n#define DHCP_PERMANENT    9\n#define DHCP_BOUND        10\n/** not yet implemented #define DHCP_RELEASING 11 */\n#define DHCP_BACKING_OFF  12\n\n/** AUTOIP cooperatation flags */\n#define DHCP_AUTOIP_COOP_STATE_OFF  0\n#define DHCP_AUTOIP_COOP_STATE_ON   1\n \n#define DHCP_BOOTREQUEST  1\n#define DHCP_BOOTREPLY    2\n\n/** DHCP message types */\n#define DHCP_DISCOVER 1\n#define DHCP_OFFER    2\n#define DHCP_REQUEST  3\n#define DHCP_DECLINE  4\n#define DHCP_ACK      5\n#define DHCP_NAK      6\n#define DHCP_RELEASE  7\n#define DHCP_INFORM   8\n\n/** DHCP hardware type, currently only ethernet is supported */\n#define DHCP_HTYPE_ETH 1\n\n#define DHCP_MAGIC_COOKIE 0x63825363UL\n\n/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */\n\n/** BootP options */\n#define DHCP_OPTION_PAD 0\n#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */\n#define DHCP_OPTION_ROUTER 3\n#define DHCP_OPTION_DNS_SERVER 6 \n#define DHCP_OPTION_HOSTNAME 12\n#define DHCP_OPTION_IP_TTL 23\n#define DHCP_OPTION_MTU 26\n#define DHCP_OPTION_BROADCAST 28\n#define DHCP_OPTION_TCP_TTL 37\n#define DHCP_OPTION_END 255\n\n/**add options for support more router by liuHan**/\n#define DHCP_OPTION_DOMAIN_NAME 15\n#define DHCP_OPTION_PRD 31\n#define DHCP_OPTION_STATIC_ROUTER 33\n#define DHCP_OPTION_VSN 43\n#define DHCP_OPTION_NB_TINS 44\n#define DHCP_OPTION_NB_TINT 46\n#define DHCP_OPTION_NB_TIS 47\n#define DHCP_OPTION_CLASSLESS_STATIC_ROUTER 121\n/** DHCP options */\n#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */\n#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */\n#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */\n\n#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */\n#define DHCP_OPTION_MESSAGE_TYPE_LEN 1\n\n#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */\n#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */\n\n#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */\n#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2\n\n#define DHCP_OPTION_T1 58 /* T1 renewal time */\n#define DHCP_OPTION_T2 59 /* T2 rebinding time */\n#define DHCP_OPTION_US 60\n#define DHCP_OPTION_CLIENT_ID 61\n#define DHCP_OPTION_TFTP_SERVERNAME 66\n#define DHCP_OPTION_BOOTFILE 67\n\n/** possible combinations of overloading the file and sname fields with options */\n#define DHCP_OVERLOAD_NONE 0\n#define DHCP_OVERLOAD_FILE 1\n#define DHCP_OVERLOAD_SNAME  2\n#define DHCP_OVERLOAD_SNAME_FILE 3\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_DHCP */\n\n#endif /*__LWIP_DHCP_H__*/\n"
  },
  {
    "path": "app/include/lwip/dns.h",
    "content": "/**\n * lwip DNS resolver header file.\n\n * Author: Jim Pettinato \n *   April 2007\n\n * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote\n *    products derived from this software without specific prior\n *    written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\n * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef __LWIP_DNS_H__\n#define __LWIP_DNS_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** DNS timer period */\n#define DNS_TMR_INTERVAL          1000\n\n/** DNS field TYPE used for \"Resource Records\" */\n#define DNS_RRTYPE_A              1     /* a host address */\n#define DNS_RRTYPE_NS             2     /* an authoritative name server */\n#define DNS_RRTYPE_MD             3     /* a mail destination (Obsolete - use MX) */\n#define DNS_RRTYPE_MF             4     /* a mail forwarder (Obsolete - use MX) */\n#define DNS_RRTYPE_CNAME          5     /* the canonical name for an alias */\n#define DNS_RRTYPE_SOA            6     /* marks the start of a zone of authority */\n#define DNS_RRTYPE_MB             7     /* a mailbox domain name (EXPERIMENTAL) */\n#define DNS_RRTYPE_MG             8     /* a mail group member (EXPERIMENTAL) */\n#define DNS_RRTYPE_MR             9     /* a mail rename domain name (EXPERIMENTAL) */\n#define DNS_RRTYPE_NULL           10    /* a null RR (EXPERIMENTAL) */\n#define DNS_RRTYPE_WKS            11    /* a well known service description */\n#define DNS_RRTYPE_PTR            12    /* a domain name pointer */\n#define DNS_RRTYPE_HINFO          13    /* host information */\n#define DNS_RRTYPE_MINFO          14    /* mailbox or mail list information */\n#define DNS_RRTYPE_MX             15    /* mail exchange */\n#define DNS_RRTYPE_TXT            16    /* text strings */\n\n/** DNS field CLASS used for \"Resource Records\" */\n#define DNS_RRCLASS_IN            1     /* the Internet */\n#define DNS_RRCLASS_CS            2     /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */\n#define DNS_RRCLASS_CH            3     /* the CHAOS class */\n#define DNS_RRCLASS_HS            4     /* Hesiod [Dyer 87] */\n#define DNS_RRCLASS_FLUSH         0x800 /* Flush bit */\n\n/* The size used for the next line is rather a hack, but it prevents including socket.h in all files\n   that include memp.h, and that would possibly break portability (since socket.h defines some types\n   and constants possibly already define by the OS).\n   Calculation rule:\n   sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */\n#define NETDB_ELEM_SIZE           (32 + 16 + DNS_MAX_NAME_LENGTH + 1)\n\n#if DNS_LOCAL_HOSTLIST\n/** struct used for local host-list */\nstruct local_hostlist_entry {\n  /** static hostname */\n  const char *name;\n  /** static host address in network byteorder */\n  ip_addr_t addr;\n  struct local_hostlist_entry *next;\n};\n#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC\n#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN\n#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN  DNS_MAX_NAME_LENGTH\n#endif\n#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))\n#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n#endif /* DNS_LOCAL_HOSTLIST */\n\n/** Callback which is invoked when a hostname is found.\n * A function of this type must be implemented by the application using the DNS resolver.\n * @param name pointer to the name that was looked up.\n * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,\n *        or NULL if the name could not be found (or on any other error).\n * @param callback_arg a user-specified callback argument passed to dns_gethostbyname\n*/\ntypedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);\n\nvoid           dns_init(void);\nvoid           dns_tmr(void);\nvoid           dns_setserver(u8_t numdns, ip_addr_t *dnsserver);\nip_addr_t      dns_getserver(u8_t numdns);\nerr_t          dns_gethostbyname(const char *hostname, ip_addr_t *addr,\n                                 dns_found_callback found, void *callback_arg);\n\n#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC\nint            dns_local_removehost(const char *hostname, const ip_addr_t *addr);\nerr_t          dns_local_addhost(const char *hostname, const ip_addr_t *addr);\n#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_DNS */\n\n#endif /* __LWIP_DNS_H__ */\n"
  },
  {
    "path": "app/include/lwip/err.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_ERR_H__\n#define __LWIP_ERR_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/arch.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** Define LWIP_ERR_T in cc.h if you want to use\n *  a different type for your platform (must be signed). */\n#ifdef LWIP_ERR_T\ntypedef LWIP_ERR_T err_t;\n#else /* LWIP_ERR_T */\ntypedef s8_t err_t;\n#endif /* LWIP_ERR_T*/\n\n/* Definitions for error constants. */\n\n#define ERR_OK          0    /* No error, everything OK. */\n#define ERR_MEM        -1    /* Out of memory error.     */\n#define ERR_BUF        -2    /* Buffer error.            */\n#define ERR_TIMEOUT    -3    /* Timeout.                 */\n#define ERR_RTE        -4    /* Routing problem.         */\n#define ERR_INPROGRESS -5    /* Operation in progress    */\n#define ERR_VAL        -6    /* Illegal value.           */\n#define ERR_WOULDBLOCK -7    /* Operation would block.   */\n\n#define ERR_IS_FATAL(e) ((e) < ERR_WOULDBLOCK)\n\n#define ERR_ABRT       -8    /* Connection aborted.      */\n#define ERR_RST        -9    /* Connection reset.        */\n#define ERR_CLSD       -10   /* Connection closed.       */\n#define ERR_CONN       -11   /* Not connected.           */\n\n#define ERR_ARG        -12   /* Illegal argument.        */\n\n#define ERR_USE        -13   /* Address in use.          */\n\n#define ERR_IF         -14   /* Low-level netif error    */\n#define ERR_ISCONN     -15   /* Already connected.       */\n\n\n#ifdef LWIP_DEBUG\nextern const char *lwip_strerr(err_t err)ICACHE_FLASH_ATTR;\n#else\n#define lwip_strerr(x) \"\"\n#endif /* LWIP_DEBUG */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_ERR_H__ */\n"
  },
  {
    "path": "app/include/lwip/icmp.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_ICMP_H__\n#define __LWIP_ICMP_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ICMP_ER 0      /* echo reply */\n#define ICMP_DUR 3     /* destination unreachable */\n#define ICMP_SQ 4      /* source quench */\n#define ICMP_RD 5      /* redirect */\n#define ICMP_ECHO 8    /* echo */\n#define ICMP_TE 11     /* time exceeded */\n#define ICMP_PP 12     /* parameter problem */\n#define ICMP_TS 13     /* timestamp */\n#define ICMP_TSR 14    /* timestamp reply */\n#define ICMP_IRQ 15    /* information request */\n#define ICMP_IR 16     /* information reply */\n\nenum icmp_dur_type {\n  ICMP_DUR_NET = 0,    /* net unreachable */\n  ICMP_DUR_HOST = 1,   /* host unreachable */\n  ICMP_DUR_PROTO = 2,  /* protocol unreachable */\n  ICMP_DUR_PORT = 3,   /* port unreachable */\n  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */\n  ICMP_DUR_SR = 5      /* source route failed */\n};\n\nenum icmp_te_type {\n  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */\n  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */\n};\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\n/** This is the standard ICMP header only that the u32_t data\n *  is splitted to two u16_t like ICMP echo needs it.\n *  This header is also used for other ICMP types that do not\n *  use the data part.\n *  ICMPײṹ\n *  ICMPײкܴԣ\n *  ýṹͬICMPġ\n */\nPACK_STRUCT_BEGIN\nstruct icmp_echo_hdr {\n  PACK_STRUCT_FIELD(u8_t type);\n  PACK_STRUCT_FIELD(u8_t code);\n  PACK_STRUCT_FIELD(u16_t chksum);\n  PACK_STRUCT_FIELD(u16_t id);\n  PACK_STRUCT_FIELD(u16_t seqno);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n//ȡICMPײֶ\n#define ICMPH_TYPE(hdr) ((hdr)->type)\n#define ICMPH_CODE(hdr) ((hdr)->code)\n\n/** Combines type and code to an u16_t ICMPײֶдӦֵ*/\n#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))\n#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))\n\n\n#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */\n\nvoid icmp_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR;\nvoid icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)ICACHE_FLASH_ATTR;\nvoid icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)ICACHE_FLASH_ATTR;\n\n#endif /* LWIP_ICMP */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_ICMP_H__ */\n"
  },
  {
    "path": "app/include/lwip/igmp.h",
    "content": "/*\n * Copyright (c) 2002 CITEL Technologies Ltd.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions \n * are met: \n * 1. Redistributions of source code must retain the above copyright \n *    notice, this list of conditions and the following disclaimer. \n * 2. Redistributions in binary form must reproduce the above copyright \n *    notice, this list of conditions and the following disclaimer in the \n *    documentation and/or other materials provided with the distribution. \n * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors \n *    may be used to endorse or promote products derived from this software \n *    without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \n * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE \n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \n * SUCH DAMAGE. \n *\n * This file is a contribution to the lwIP TCP/IP stack.\n * The Swedish Institute of Computer Science and Adam Dunkels\n * are specifically granted permission to redistribute this\n * source code.\n*/\n\n#ifndef __LWIP_IGMP_H__\n#define __LWIP_IGMP_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/pbuf.h\"\n\n#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n/* IGMP timer */\n#define IGMP_TMR_INTERVAL              100 /* Milliseconds */\n#define IGMP_V1_DELAYING_MEMBER_TMR   (1000/IGMP_TMR_INTERVAL)\n#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)\n\n/* MAC Filter Actions, these are passed to a netif's\n * igmp_mac_filter callback function. */\n#define IGMP_DEL_MAC_FILTER            0\n#define IGMP_ADD_MAC_FILTER            1\n\n\n/**\n * igmp group structure - there is\n * a list of groups for each interface\n * these should really be linked from the interface, but\n * if we keep them separate we will not affect the lwip original code\n * too much\n * \n * There will be a group for the all systems group address but this \n * will not run the state machine as it is used to kick off reports\n * from all the other groups\n */\nstruct igmp_group {\n  /** next link */\n  struct igmp_group *next;\n  /** interface on which the group is active */\n  struct netif      *netif;\n  /** multicast address */\n  ip_addr_t          group_address;\n  /** signifies we were the last person to report */\n  u8_t               last_reporter_flag;\n  /** current state of the group */\n  u8_t               group_state;\n  /** timer for reporting, negative is OFF */\n  u16_t              timer;\n  /** counter of simultaneous uses */\n  u8_t               use;\n};\n\n/*  Prototypes */\nvoid   igmp_init(void)ICACHE_FLASH_ATTR;\nerr_t  igmp_start(struct netif *netif)ICACHE_FLASH_ATTR;\nerr_t  igmp_stop(struct netif *netif)ICACHE_FLASH_ATTR;\nvoid   igmp_report_groups(struct netif *netif)ICACHE_FLASH_ATTR;\nstruct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR;\nvoid   igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)ICACHE_FLASH_ATTR;\nerr_t  igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR;\nerr_t  igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)ICACHE_FLASH_ATTR;\nvoid   igmp_tmr(void)ICACHE_FLASH_ATTR;\n#define LWIP_RAND()  r_rand()\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_IGMP */\n\n#endif /* __LWIP_IGMP_H__ */\n"
  },
  {
    "path": "app/include/lwip/inet.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_INET_H__\n#define __LWIP_INET_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/def.h\"\n#include \"lwip/ip_addr.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** For compatibility with BSD code */\nstruct in_addr {\n  u32_t s_addr;\n};\n\n/** 255.255.255.255 */\n#define INADDR_NONE         IPADDR_NONE\n/** 127.0.0.1 */\n#define INADDR_LOOPBACK     IPADDR_LOOPBACK\n/** 0.0.0.0 */\n#define INADDR_ANY          IPADDR_ANY\n/** 255.255.255.255 */\n#define INADDR_BROADCAST    IPADDR_BROADCAST\n\n/* Definitions of the bits in an Internet address integer.\n\n   On subnets, host and network parts are found according to\n   the subnet mask, not these masks.  */\n#define IN_CLASSA(a)        IP_CLASSA(a)\n#define IN_CLASSA_NET       IP_CLASSA_NET\n#define IN_CLASSA_NSHIFT    IP_CLASSA_NSHIFT\n#define IN_CLASSA_HOST      IP_CLASSA_HOST\n#define IN_CLASSA_MAX       IP_CLASSA_MAX\n\n#define IN_CLASSB(b)        IP_CLASSB(b)\n#define IN_CLASSB_NET       IP_CLASSB_NET\n#define IN_CLASSB_NSHIFT    IP_CLASSB_NSHIFT\n#define IN_CLASSB_HOST      IP_CLASSB_HOST\n#define IN_CLASSB_MAX       IP_CLASSB_MAX\n\n#define IN_CLASSC(c)        IP_CLASSC(c)\n#define IN_CLASSC_NET       IP_CLASSC_NET\n#define IN_CLASSC_NSHIFT    IP_CLASSC_NSHIFT\n#define IN_CLASSC_HOST      IP_CLASSC_HOST\n#define IN_CLASSC_MAX       IP_CLASSC_MAX\n\n#define IN_CLASSD(d)        IP_CLASSD(d)\n#define IN_CLASSD_NET       IP_CLASSD_NET     /* These ones aren't really */\n#define IN_CLASSD_NSHIFT    IP_CLASSD_NSHIFT  /*   net and host fields, but */\n#define IN_CLASSD_HOST      IP_CLASSD_HOST    /*   routing needn't know. */\n#define IN_CLASSD_MAX       IP_CLASSD_MAX\n\n#define IN_MULTICAST(a)     IP_MULTICAST(a)\n\n#define IN_EXPERIMENTAL(a)  IP_EXPERIMENTAL(a)\n#define IN_BADCLASS(a)      IP_BADCLASS(a)\n\n#define IN_LOOPBACKNET      IP_LOOPBACKNET\n\n#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))\n#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr)   (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))\n/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */\n#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr)   ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr))\n\n/* directly map this to the lwip internal functions */\n#define inet_addr(cp)         ipaddr_addr(cp)\n#define inet_aton(cp, addr)   ipaddr_aton(cp, (ip_addr_t*)addr)\n#define inet_ntoa(addr)       ipaddr_ntoa((ip_addr_t*)&(addr))\n#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_INET_H__ */\n"
  },
  {
    "path": "app/include/lwip/inet_chksum.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_INET_CHKSUM_H__\n#define __LWIP_INET_CHKSUM_H__\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/pbuf.h\"\n#include \"lwip/ip_addr.h\"\n\n/** Swap the bytes in an u16_t: much like htons() for little-endian */\n#ifndef SWAP_BYTES_IN_WORD\n#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)\n/* little endian and PLATFORM_BYTESWAP defined */\n#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)\n#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */\n/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */\n#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)\n#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/\n#endif /* SWAP_BYTES_IN_WORD */\n\n/** Split an u32_t in two u16_ts and add them up */\n#ifndef FOLD_U32T\n#define FOLD_U32T(u)          (((u) >> 16) + ((u) & 0x0000ffffUL))\n#endif\n\n#if LWIP_CHECKSUM_ON_COPY\n/** Function-like macro: same as MEMCPY but returns the checksum of copied data\n    as u16_t */\n#ifndef LWIP_CHKSUM_COPY\n#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)\n#ifndef LWIP_CHKSUM_COPY_ALGORITHM\n#define LWIP_CHKSUM_COPY_ALGORITHM 1\n#endif /* LWIP_CHKSUM_COPY_ALGORITHM */\n#endif /* LWIP_CHKSUM_COPY */\n#else /* LWIP_CHECKSUM_ON_COPY */\n#define LWIP_CHKSUM_COPY_ALGORITHM 0\n#endif /* LWIP_CHECKSUM_ON_COPY */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nu16_t inet_chksum(void *dataptr, u16_t len)ICACHE_FLASH_ATTR;\nu16_t inet_chksum_pbuf(struct pbuf *p)ICACHE_FLASH_ATTR;\nu16_t inet_chksum_pseudo(struct pbuf *p,\n       ip_addr_t *src, ip_addr_t *dest,\n       u8_t proto, u16_t proto_len)ICACHE_FLASH_ATTR;\nu16_t inet_chksum_pseudo_partial(struct pbuf *p,\n       ip_addr_t *src, ip_addr_t *dest,\n       u8_t proto, u16_t proto_len, u16_t chksum_len)ICACHE_FLASH_ATTR;\n#if LWIP_CHKSUM_COPY_ALGORITHM\nu16_t lwip_chksum_copy(void *dst, const void *src, u16_t len)ICACHE_FLASH_ATTR;\n#endif /* LWIP_CHKSUM_COPY_ALGORITHM */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_INET_H__ */\n\n"
  },
  {
    "path": "app/include/lwip/init.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_INIT_H__\n#define __LWIP_INIT_H__\n\n#include \"lwip/opt.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** X.x.x: Major version of the stack */\n#define LWIP_VERSION_MAJOR      1U\n/** x.X.x: Minor version of the stack */\n#define LWIP_VERSION_MINOR      4U\n/** x.x.X: Revision of the stack */\n#define LWIP_VERSION_REVISION   0U\n/** For release candidates, this is set to 1..254\n  * For official releases, this is set to 255 (LWIP_RC_RELEASE)\n  * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */\n#define LWIP_VERSION_RC         2U\n\n/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */\n#define LWIP_RC_RELEASE         255U\n/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */\n#define LWIP_RC_DEVELOPMENT     0U\n\n#define LWIP_VERSION_IS_RELEASE     (LWIP_VERSION_RC == LWIP_RC_RELEASE)\n#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT)\n#define LWIP_VERSION_IS_RC          ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT))\n\n/** Provides the version of the stack */\n#define LWIP_VERSION   (LWIP_VERSION_MAJOR << 24   | LWIP_VERSION_MINOR << 16 | \\\n                        LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)\n\n/* Modules initialization */\nvoid lwip_init(void) ICACHE_FLASH_ATTR;\n//void lwip_init(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_INIT_H__ */\n"
  },
  {
    "path": "app/include/lwip/ip.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_IP_H__\n#define __LWIP_IP_H__\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/def.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/err.h\"\n#include \"lwip/netif.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** Currently, the function ip_output_if_opt() is only used with IGMP */\n#define IP_OPTIONS_SEND   LWIP_IGMP\n\n#define IP_HLEN 20\n\n#define IP_PROTO_ICMP    1\n#define IP_PROTO_IGMP    2\n#define IP_PROTO_UDP     17\n#define IP_PROTO_UDPLITE 136\n#define IP_PROTO_TCP     6\n\n/* This is passed as the destination address to ip_output_if (not\n   to ip_output), meaning that an IP header already is constructed\n   in the pbuf. This is used when TCP retransmits. */\n#ifdef IP_HDRINCL\n#undef IP_HDRINCL\n#endif /* IP_HDRINCL */\n#define IP_HDRINCL  NULL\n\n#if LWIP_NETIF_HWADDRHINT\n#define IP_PCB_ADDRHINT ;u8_t addr_hint\n#else\n#define IP_PCB_ADDRHINT\n#endif /* LWIP_NETIF_HWADDRHINT */\n\n/* This is the common part of all PCB types. It needs to be at the\n   beginning of a PCB type definition. It is located here so that\n   changes to this common part are made in one location instead of\n   having to change all PCB structs. */\n#define IP_PCB \\\n  /* ip addresses in network byte order */ \\\n  ip_addr_t local_ip; \\\n  ip_addr_t remote_ip; \\\n   /* Socket options */  \\\n  u8_t so_options;      \\\n   /* Type Of Service */ \\\n  u8_t tos;              \\\n  /* Time To Live */     \\\n  u8_t ttl               \\\n  /* link layer address resolution hint */ \\\n  IP_PCB_ADDRHINT\n\nstruct ip_pcb {\n/* Common members of all PCB types */\n  IP_PCB;\n};\n\n/*\n * Option flags per-socket. These are the same like SO_XXX.\n */\n/*#define SOF_DEBUG       (u8_t)0x01U     Unimplemented: turn on debugging info recording */\n#define SOF_ACCEPTCONN    (u8_t)0x02U  /* socket has had listen() */\n#define SOF_REUSEADDR     (u8_t)0x04U  /* allow local address reuse */\n#define SOF_KEEPALIVE     (u8_t)0x08U  /* keep connections alive */\n/*#define SOF_DONTROUTE   (u8_t)0x10U     Unimplemented: just use interface addresses */\n#define SOF_BROADCAST     (u8_t)0x20U  /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */\n/*#define SOF_USELOOPBACK (u8_t)0x40U     Unimplemented: bypass hardware when possible */\n#define SOF_LINGER        (u8_t)0x80U  /* linger on close if data present */\n/*#define SOF_OOBINLINE   (u16_t)0x0100U     Unimplemented: leave received OOB data in line */\n/*#define SOF_REUSEPORT   (u16_t)0x0200U     Unimplemented: allow local address & port reuse */\n\n/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */\n#define SOF_INHERITED   (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)\n\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct ip_hdr {\n  /* version / header length / type of service */\n  PACK_STRUCT_FIELD(u16_t _v_hl_tos);\n  /* total length */\n  PACK_STRUCT_FIELD(u16_t _len);\n  /* identification */\n  PACK_STRUCT_FIELD(u16_t _id);\n  /* fragment offset field */\n  PACK_STRUCT_FIELD(u16_t _offset);\n#define IP_RF 0x8000        /* reserved fragment flag */\n#define IP_DF 0x4000        /* dont fragment flag */\n#define IP_MF 0x2000        /* more fragments flag */\n#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */\n  /* time to live */\n  PACK_STRUCT_FIELD(u8_t _ttl);\n  /* protocol*/\n  PACK_STRUCT_FIELD(u8_t _proto);\n  /* checksum */\n  PACK_STRUCT_FIELD(u16_t _chksum);\n  /* source and destination IP addresses */\n  PACK_STRUCT_FIELD(ip_addr_p_t src);\n  PACK_STRUCT_FIELD(ip_addr_p_t dest); \n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#define IPH_V(hdr)  (ntohs((hdr)->_v_hl_tos) >> 12)\n#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)\n#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)\n#define IPH_LEN(hdr) ((hdr)->_len)\n#define IPH_ID(hdr) ((hdr)->_id)\n#define IPH_OFFSET(hdr) ((hdr)->_offset)\n#define IPH_TTL(hdr) ((hdr)->_ttl)\n#define IPH_PROTO(hdr) ((hdr)->_proto)\n#define IPH_CHKSUM(hdr) ((hdr)->_chksum)\n\n#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))\n#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)\n#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)\n#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)\n#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)\n#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)\n#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)\n\n/** The interface that provided the packet for the current callback invocation. */\nextern struct netif *current_netif;\n/** Header of the input packet currently being processed. */\nextern const struct ip_hdr *current_header;\n/** Source IP address of current_header */\nextern ip_addr_t current_iphdr_src;\n/** Destination IP address of current_header */\nextern ip_addr_t current_iphdr_dest;\n\n#define ip_init() /* Compatibility define, not init needed. */\nstruct netif *ip_route(ip_addr_t *dest)ICACHE_FLASH_ATTR;\nstruct netif *ip_router(ip_addr_t *dest, ip_addr_t *source);\n\nerr_t ip_input(struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR;\nerr_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,\n       u8_t ttl, u8_t tos, u8_t proto)ICACHE_FLASH_ATTR;\nerr_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,\n       u8_t ttl, u8_t tos, u8_t proto,\n       struct netif *netif)ICACHE_FLASH_ATTR;\n#if LWIP_NETIF_HWADDRHINT\nerr_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,\n       u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)ICACHE_FLASH_ATTR;\n#endif /* LWIP_NETIF_HWADDRHINT */\n#if IP_OPTIONS_SEND\nerr_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,\n       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,\n       u16_t optlen)ICACHE_FLASH_ATTR;\n#endif /* IP_OPTIONS_SEND */\n/** Get the interface that received the current packet.\n * This function must only be called from a receive callback (udp_recv,\n * raw_recv, tcp_accept). It will return NULL otherwise. */\n#define ip_current_netif()  (current_netif)\n/** Get the IP header of the current packet.\n * This function must only be called from a receive callback (udp_recv,\n * raw_recv, tcp_accept). It will return NULL otherwise. */\n#define ip_current_header() (current_header)\n/** Source IP address of current_header */\n#define ip_current_src_addr()  (&current_iphdr_src)\n/** Destination IP address of current_header */\n#define ip_current_dest_addr() (&current_iphdr_dest)\n\n#if IP_DEBUG\nvoid ip_debug_print(struct pbuf *p)ICACHE_FLASH_ATTR;\n#else\n#define ip_debug_print(p)\n#endif /* IP_DEBUG */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_IP_H__ */\n\n\n"
  },
  {
    "path": "app/include/lwip/ip_addr.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_IP_ADDR_H__\n#define __LWIP_IP_ADDR_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/def.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* This is the aligned version of ip_addr_t,\n   used as local variable, on the stack, etc. */\nstruct ip_addr {\n  u32_t addr;\n};\n\n/* This is the packed version of ip_addr_t,\n   used in network headers that are itself packed */\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct ip_addr_packed {\n  PACK_STRUCT_FIELD(u32_t addr);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n/** ip_addr_t uses a struct for convenience only, so that the same defines can\n * operate both on ip_addr_t as well as on ip_addr_p_t. */\ntypedef struct ip_addr ip_addr_t;\ntypedef struct ip_addr_packed ip_addr_p_t;\n\n/*\n * struct ipaddr2 is used in the definition of the ARP packet format in\n * order to support compilers that don't have structure packing.\n */\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct ip_addr2 {\n  PACK_STRUCT_FIELD(u16_t addrw[2]);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n/* Forward declaration to not include netif.h */\nstruct netif;\n\nextern const ip_addr_t ip_addr_any;\nextern const ip_addr_t ip_addr_broadcast;\n\n/** IP_ADDR_ can be used as a fixed IP address\n *  for the wildcard and the broadcast address\n */\n#define IP_ADDR_ANY         ((ip_addr_t *)&ip_addr_any)\n#define IP_ADDR_BROADCAST   ((ip_addr_t *)&ip_addr_broadcast)\n\n/** 255.255.255.255 */\n#define IPADDR_NONE         ((u32_t)0xffffffffUL)\n/** 127.0.0.1 */\n#define IPADDR_LOOPBACK     ((u32_t)0x7f000001UL)\n/** 0.0.0.0 */\n#define IPADDR_ANY          ((u32_t)0x00000000UL)\n/** 255.255.255.255 */\n#define IPADDR_BROADCAST    ((u32_t)0xffffffffUL)\n\n/* Definitions of the bits in an Internet address integer.\n\n   On subnets, host and network parts are found according to\n   the subnet mask, not these masks.  */\n#define IP_CLASSA(a)        ((((u32_t)(a)) & 0x80000000UL) == 0)\n#define IP_CLASSA_NET       0xff000000\n#define IP_CLASSA_NSHIFT    24\n#define IP_CLASSA_HOST      (0xffffffff & ~IP_CLASSA_NET)\n#define IP_CLASSA_MAX       128\n\n#define IP_CLASSB(a)        ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)\n#define IP_CLASSB_NET       0xffff0000\n#define IP_CLASSB_NSHIFT    16\n#define IP_CLASSB_HOST      (0xffffffff & ~IP_CLASSB_NET)\n#define IP_CLASSB_MAX       65536\n\n#define IP_CLASSC(a)        ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)\n#define IP_CLASSC_NET       0xffffff00\n#define IP_CLASSC_NSHIFT    8\n#define IP_CLASSC_HOST      (0xffffffff & ~IP_CLASSC_NET)\n\n#define IP_CLASSD(a)        (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)\n#define IP_CLASSD_NET       0xf0000000          /* These ones aren't really */\n#define IP_CLASSD_NSHIFT    28                  /*   net and host fields, but */\n#define IP_CLASSD_HOST      0x0fffffff          /*   routing needn't know. */\n#define IP_MULTICAST(a)     IP_CLASSD(a)\n\n#define IP_EXPERIMENTAL(a)  (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)\n#define IP_BADCLASS(a)      (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)\n\n#define IP_LOOPBACKNET      127                 /* official! */\n\n\n#if BYTE_ORDER == BIG_ENDIAN\n/** Set an IP address given by the four byte-parts */\n#define IP4_ADDR(ipaddr, a,b,c,d) \\\n        (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \\\n                         ((u32_t)((b) & 0xff) << 16) | \\\n                         ((u32_t)((c) & 0xff) << 8)  | \\\n                          (u32_t)((d) & 0xff)\n#else\n/** Set an IP address given by the four byte-parts.\n    Little-endian version that prevents the use of htonl. */\n#define IP4_ADDR(ipaddr, a,b,c,d) \\\n        (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \\\n                         ((u32_t)((c) & 0xff) << 16) | \\\n                         ((u32_t)((b) & 0xff) << 8)  | \\\n                          (u32_t)((a) & 0xff)\n#endif\n\n/** MEMCPY-like copying of IP addresses where addresses are known to be\n * 16-bit-aligned if the port is correctly configured (so a port could define\n * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */\n#ifndef IPADDR2_COPY\n#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t))\n#endif\n\n/** Copy IP address - faster than ip_addr_set: no NULL check */\n#define ip_addr_copy(dest, src) ((dest).addr = (src).addr)\n/** Safely copy one IP address to another (src may be NULL) */\n#define ip_addr_set(dest, src) ((dest)->addr = \\\n                                    ((src) == NULL ? 0 : \\\n                                    (src)->addr))\n/** Set complete address to zero */\n#define ip_addr_set_zero(ipaddr)      ((ipaddr)->addr = 0)\n/** Set address to IPADDR_ANY (no need for htonl()) */\n#define ip_addr_set_any(ipaddr)       ((ipaddr)->addr = IPADDR_ANY)\n/** Set address to loopback address */\n#define ip_addr_set_loopback(ipaddr)  ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))\n/** Safely copy one IP address to another and change byte order\n * from host- to network-order. */\n#define ip_addr_set_hton(dest, src) ((dest)->addr = \\\n                               ((src) == NULL ? 0:\\\n                               htonl((src)->addr)))\n/** IPv4 only: set the IP address given as an u32_t */\n#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))\n/** IPv4 only: get the IP address as an u32_t */\n#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)\n\n/** Get the network address by combining host address with netmask */\n#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr))\n\n/**\n * Determine if two address are on the same network.\n *\n * @arg addr1 IP address 1\n * @arg addr2 IP address 2\n * @arg mask network identifier mask\n * @return !0 if the network identifiers of both address match\n */\n#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \\\n                                              (mask)->addr) == \\\n                                             ((addr2)->addr & \\\n                                              (mask)->addr))\n#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)\n\n#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY)\n\n#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif))\nu8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)ICACHE_FLASH_ATTR;\n\n#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr)\nu8_t ip4_addr_netmask_valid(u32_t netmask)ICACHE_FLASH_ATTR;\n\n#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL))\n\n#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL))\n\n#define ip_addr_debug_print(debug, ipaddr) \\\n  LWIP_DEBUGF(debug, (\"%\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F,             \\\n                      ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0,       \\\n                      ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0,       \\\n                      ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0,       \\\n                      ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0))\n\n/* Get one byte from the 4-byte address */\n#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])\n#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])\n#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])\n#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])\n/* These are cast to u16_t, with the intent that they are often arguments\n * to printf using the U16_F format from cc.h. */\n#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))\n#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))\n#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))\n#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))\n\n/** For backwards compatibility */\n#define ip_ntoa(ipaddr)  ipaddr_ntoa(ipaddr)\n\nu32_t ipaddr_addr(const char *cp)ICACHE_FLASH_ATTR;\nint ipaddr_aton(const char *cp, ip_addr_t *addr)ICACHE_FLASH_ATTR;\n/** returns ptr to static buffer; not reentrant! */\nchar *ipaddr_ntoa(const ip_addr_t *addr)ICACHE_FLASH_ATTR;\nchar *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)ICACHE_FLASH_ATTR;\n\n#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \\\n    ip4_addr2_16(ipaddr), \\\n    ip4_addr3_16(ipaddr), \\\n    ip4_addr4_16(ipaddr)\n\n#define IPSTR \"%d.%d.%d.%d\"\n\nstruct ip_info {\n    struct ip_addr ip;\n    struct ip_addr netmask;\n    struct ip_addr gw;\n};\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_IP_ADDR_H__ */\n"
  },
  {
    "path": "app/include/lwip/ip_frag.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Jani Monoses <jani@iv.ro>\n *\n */\n\n#ifndef __LWIP_IP_FRAG_H__\n#define __LWIP_IP_FRAG_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/err.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/ip.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if IP_REASSEMBLY\n/* The IP reassembly timer interval in milliseconds. */\n#define IP_TMR_INTERVAL 1000\n\n/* IP reassembly helper struct.\n * This is exported because memp needs to know the size.\n */\nstruct ip_reassdata {\n  struct ip_reassdata *next;\n  struct pbuf *p;\n  struct ip_hdr iphdr;\n  u16_t datagram_len;\n  u8_t flags;\n  u8_t timer;\n};\n\nvoid ip_reass_init(void)ICACHE_FLASH_ATTR;\nvoid ip_reass_tmr(void)ICACHE_FLASH_ATTR;\nstruct pbuf * ip_reass(struct pbuf *p)ICACHE_FLASH_ATTR;\n#endif /* IP_REASSEMBLY */\n\n#if IP_FRAG\n#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF\n/** A custom pbuf that holds a reference to another pbuf, which is freed\n * when this custom pbuf is freed. This is used to create a custom PBUF_REF\n * that points into the original pbuf. */\nstruct pbuf_custom_ref {\n  /** 'base class' */\n  struct pbuf_custom pc;\n  /** pointer to the original pbuf that is referenced */\n  struct pbuf *original;\n};\n#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */\n\nerr_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)ICACHE_FLASH_ATTR;\n#endif /* IP_FRAG */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_IP_FRAG_H__ */\n"
  },
  {
    "path": "app/include/lwip/mdns.h",
    "content": "/**\n * lwip MDNS resolver header file.\n *\n * Created on: Jul 29, 2010\n * Author: Daniel Toma\n\n\n * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote\n *    products derived from this software without specific prior\n *    written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\n * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef __LWIP_DNS_H__\n#define __LWIP_DNS_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */\n\n/** DNS timer period */\n#define DNS_TMR_INTERVAL          1000\n\n/** mDNS Address offset flag*/\n#define DNS_OFFSET_FLAG          0xC0     /* the offset flag in the DNS message */\n#define DNS_DEFAULT_OFFSET       0x0C     /* the offset is set at the beginning of the DNS message */\n\n#define DNS_IP_ADDR_LEN           4\n\n\n/** DNS field TYPE used for \"Resource Records\" */\n#define DNS_RRTYPE_A              1     /* a host address */\n#define DNS_RRTYPE_NS             2     /* an authoritative name server */\n#define DNS_RRTYPE_MD             3     /* a mail destination (Obsolete - use MX) */\n#define DNS_RRTYPE_MF             4     /* a mail forwarder (Obsolete - use MX) */\n#define DNS_RRTYPE_CNAME          5     /* the canonical name for an alias */\n#define DNS_RRTYPE_SOA            6     /* marks the start of a zone of authority */\n#define DNS_RRTYPE_MB             7     /* a mailbox domain name (EXPERIMENTAL) */\n#define DNS_RRTYPE_MG             8     /* a mail group member (EXPERIMENTAL) */\n#define DNS_RRTYPE_MR             9     /* a mail rename domain name (EXPERIMENTAL) */\n#define DNS_RRTYPE_NULL           10    /* a null RR (EXPERIMENTAL) */\n#define DNS_RRTYPE_WKS            11    /* a well known service description */\n#define DNS_RRTYPE_PTR            12    /* a domain name pointer */\n#define DNS_RRTYPE_HINFO          13    /* host information */\n#define DNS_RRTYPE_MINFO          14    /* mailbox or mail list information */\n#define DNS_RRTYPE_MX             15    /* mail exchange */\n#define DNS_RRTYPE_TXT            16    /* text strings */\n#define DNS_RRTYPE_SRV            33    /* Service record */\n#define DNS_RRTYPE_OPT            41    /* EDNS0 OPT record */\n#define DNS_RRTYPE_TSIG           250   /* Transaction Signature */\n#define DNS_RRTYPE_ANY            255   /*Not a DNS type, but a DNS query type, meaning \"all types\"*/\n\n/* DNS field CLASS used for \"Resource Records\" */\n#define DNS_RRCLASS_IN            1    /* the Internet */\n#define DNS_RRCLASS_CS            2     /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */\n#define DNS_RRCLASS_CH            3     /* the CHAOS class */\n#define DNS_RRCLASS_HS            4     /* Hesiod [Dyer 87] */\n#define DNS_RRCLASS_FLUSH         0x800 /* Flush bit */\n#define DNS_RRCLASS_FLUSH_IN      0x8001/* Flush bit and Internet*/\n\n/** Callback which is invoked when a hostname is found.\n * A function of this type must be implemented by the application using the DNS resolver.\n * @param name pointer to the name that was looked up.\n * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,\n *        or NULL if the name could not be found (or on any other error).\n * @param callback_arg a user-specified callback argument passed to dns_gethostbyname\n*/\n#ifndef _MDNS_INFO\n#define _MDNS_INFO\nstruct mdns_info {\n\tchar *host_name;\n\tchar *server_name;\n\tuint16 server_port;\n\tunsigned long ipAddr;\n\tchar *txt_data[10];\n};\n#endif\n//void \t\t   mdns_enable(void);\n//void           mdns_disable(void);\n//void           mdns_init(struct mdns_info *info);\n//void           mdns_close(void);\n//char* \t\t   mdns_get_hostname(void);\n//void           mdns_set_hostname(char *name);\n//void           mdns_set_servername(const char *name);\n//char*          mdns_get_servername(void);\n//void           mdns_server_unregister(void);\n//void           mdns_server_register(void) ;\n//void           mdns_tmr(void);\n//void           Delay(unsigned long ulSeconds);\n\n#endif /* LWIP_DNS */\n\n#endif /* __LWIP_DNS_H__ */\n"
  },
  {
    "path": "app/include/lwip/mem.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_MEM_H__\n#define __LWIP_MEM_H__\n\n#include \"lwip/opt.h\"\n//#include \"mem_manager.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if MEM_LIBC_MALLOC\n\n#include <stddef.h> /* for size_t */\n\ntypedef size_t mem_size_t;\n\n/* aliases for C library malloc() */\n#define mem_init()\n/* in case C library malloc() needs extra protection,\n * allow these defines to be overridden.\n */\n#ifndef MEMLEAK_DEBUG\n#ifndef mem_free\n#define mem_free vPortFree\n#endif\n#ifndef mem_malloc\n#define mem_malloc pvPortMalloc\n#endif\n#ifndef mem_calloc\n#define mem_calloc pvPortCalloc\n#endif\n#ifndef mem_realloc\n#define mem_realloc pvPortRealloc\n#endif\n#ifndef mem_zalloc\n#define mem_zalloc pvPortZalloc\n#endif\n#else\n#ifndef mem_free\n#define mem_free(s) \\\ndo{\\\n\tconst char *file = mem_debug_file;\\\n    vPortFree(s, file, __LINE__);\\\n}while(0)\n#endif\n#ifndef mem_malloc\n#define mem_malloc(s) ({const char *file = mem_debug_file; pvPortMalloc(s, file, __LINE__);})\n#endif\n#ifndef mem_calloc\n#define mem_calloc(s) ({const char *file = mem_debug_file; pvPortCalloc(s, file, __LINE__);})\n#endif\n#ifndef mem_realloc\n#define mem_realloc(p, s) ({const char *file = mem_debug_file; pvPortRealloc(p, s, file, __LINE__);})\n#endif\n#ifndef mem_zalloc\n#define mem_zalloc(s) ({const char *file = mem_debug_file; pvPortZalloc(s, file, __LINE__);})\n#endif\n\n#endif\n\n#ifndef os_malloc\n#define os_malloc(s) mem_malloc((s))\n#endif\n#ifndef os_realloc\n#define os_realloc(p, s) mem_realloc((p), (s))\n#endif\n#ifndef os_zalloc\n#define os_zalloc(s) mem_zalloc((s))\n#endif\n#ifndef os_free\n#define os_free(p) mem_free((p))\n#endif\n\n/* Since there is no C library allocation function to shrink memory without\n   moving it, define this to nothing. */\n#ifndef mem_trim\n#define mem_trim(mem, size) (mem)\n#endif\n#else /* MEM_LIBC_MALLOC */\n\n/* MEM_SIZE would have to be aligned, but using 64000 here instead of\n * 65535 leaves some room for alignment...\n */\n#if MEM_SIZE > 64000l\ntypedef u32_t mem_size_t;\n#define MEM_SIZE_F U32_F\n#else\ntypedef u16_t mem_size_t;\n#define MEM_SIZE_F U16_F\n#endif /* MEM_SIZE > 64000 */\n\n#if MEM_USE_POOLS\n/** mem_init is not used when using pools instead of a heap */\n#define mem_init()\n/** mem_trim is not used when using pools instead of a heap:\n    we can't free part of a pool element and don't want to copy the rest */\n#define mem_trim(mem, size) (mem)\n#else /* MEM_USE_POOLS */\n/* lwIP alternative malloc */\nvoid  mem_init(void)ICACHE_FLASH_ATTR;\nvoid *mem_trim(void *mem, mem_size_t size)ICACHE_FLASH_ATTR;\n#endif /* MEM_USE_POOLS */\nvoid *mem_malloc(mem_size_t size)ICACHE_FLASH_ATTR;\nvoid *mem_calloc(mem_size_t count, mem_size_t size)ICACHE_FLASH_ATTR;\nvoid  mem_free(void *mem)ICACHE_FLASH_ATTR;\n#endif /* MEM_LIBC_MALLOC */\n\n/** Calculate memory size for an aligned buffer - returns the next highest\n * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and\n * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4).\n */\n#ifndef LWIP_MEM_ALIGN_SIZE\n#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))\n#endif\n\n/** Calculate safe memory size for an aligned buffer when using an unaligned\n * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the\n * start (e.g. if buffer is u8_t[] and actual data will be u32_t*)\n */\n#ifndef LWIP_MEM_ALIGN_BUFFER\n#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1))\n#endif\n\n/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT\n * so that ADDR % MEM_ALIGNMENT == 0\n */\n#ifndef LWIP_MEM_ALIGN\n#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_MEM_H__ */\n"
  },
  {
    "path": "app/include/lwip/memp.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#ifndef __LWIP_MEMP_H__\n#define __LWIP_MEMP_H__\n\n#include \"lwip/opt.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */\ntypedef enum {\n#define LWIP_MEMPOOL(name,num,size,desc, attr)  MEMP_##name,\n#include \"lwip/memp_std.h\"\n  MEMP_MAX\n} memp_t;\n\n#if MEM_USE_POOLS\n/* Use a helper type to get the start and end of the user \"memory pools\" for mem_malloc */\ntypedef enum {\n    /* Get the first (via:\n       MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/\n    MEMP_POOL_HELPER_FIRST = ((u8_t)\n#define LWIP_MEMPOOL(name,num,size,desc)\n#define LWIP_MALLOC_MEMPOOL_START 1\n#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0\n#define LWIP_MALLOC_MEMPOOL_END\n#include \"lwip/memp_std.h\"\n    ) ,\n    /* Get the last (via:\n       MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */\n    MEMP_POOL_HELPER_LAST = ((u8_t)\n#define LWIP_MEMPOOL(name,num,size,desc)\n#define LWIP_MALLOC_MEMPOOL_START\n#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *\n#define LWIP_MALLOC_MEMPOOL_END 1\n#include \"lwip/memp_std.h\"\n    )\n} memp_pool_helper_t;\n\n/* The actual start and stop values are here (cast them over)\n   We use this helper type and these defines so we can avoid using const memp_t values */\n#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)\n#define MEMP_POOL_LAST   ((memp_t) MEMP_POOL_HELPER_LAST)\n#endif /* MEM_USE_POOLS */\n\n#if MEMP_MEM_MALLOC || MEM_USE_POOLS\nextern const u32_t memp_sizes[MEMP_MAX];\n#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */\n\n#if MEMP_MEM_MALLOC\n\n#include \"mem.h\"\n\n#define memp_init()\n#define memp_malloc(type)     mem_malloc(memp_sizes[type])\n#define memp_free(type, mem)  mem_free(mem)\n\n#else /* MEMP_MEM_MALLOC */\n\n#if MEM_USE_POOLS\n/** This structure is used to save the pool one element came from. */\nstruct memp_malloc_helper\n{\n   memp_t poolnr;\n};\n#endif /* MEM_USE_POOLS */\n\nvoid  memp_init(void)ICACHE_FLASH_ATTR;\n\n#if MEMP_OVERFLOW_CHECK\nvoid *memp_malloc_fn(memp_t type, const char* file, const int line)ICACHE_FLASH_ATTR;\n#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__)\n#else\nvoid *memp_malloc(memp_t type)ICACHE_FLASH_ATTR;\n#endif\nvoid  memp_free(memp_t type, void *mem)ICACHE_FLASH_ATTR;\n\n#endif /* MEMP_MEM_MALLOC */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_MEMP_H__ */\n"
  },
  {
    "path": "app/include/lwip/memp_std.h",
    "content": "/*\n * SETUP: Make sure we define everything we will need.\n *\n * We have create three types of pools:\n *   1) MEMPOOL - standard pools\n *   2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c\n *   3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct\n *\n * If the include'r doesn't require any special treatment of each of the types\n * above, then will declare #2 & #3 to be just standard mempools.\n */\n#ifndef LWIP_MALLOC_MEMPOOL\n/* This treats \"malloc pools\" just like any other pool.\n   The pools are a little bigger to provide 'size' as the amount of user data. */\n#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), \"MALLOC_\"#size, attr)\n#define LWIP_MALLOC_MEMPOOL_START\n#define LWIP_MALLOC_MEMPOOL_END\n#endif /* LWIP_MALLOC_MEMPOOL */ \n\n#ifndef LWIP_PBUF_MEMPOOL\n/* This treats \"pbuf pools\" just like any other pool.\n * Allocates buffers for a pbuf struct AND a payload size */\n#define LWIP_PBUF_MEMPOOL(name, num, payload, desc, attr) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc, attr)\n#endif /* LWIP_PBUF_MEMPOOL */\n\n\n/*\n * A list of internal pools used by LWIP.\n *\n * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description)\n *     creates a pool name MEMP_pool_name. description is used in stats.c\n */\n#if LWIP_RAW\nLWIP_MEMPOOL(RAW_PCB,        MEMP_NUM_RAW_PCB,         sizeof(struct raw_pcb),        \"RAW_PCB\", DMEM_ATTR)\n#endif /* LWIP_RAW */\n\n#if LWIP_UDP\nLWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        \"UDP_PCB\", DMEM_ATTR)\n#endif /* LWIP_UDP */\n\n#if LWIP_TCP\nLWIP_MEMPOOL(TCP_PCB,        MEMP_NUM_TCP_PCB,         sizeof(struct tcp_pcb),        \"TCP_PCB\", DMEM_ATTR)\nLWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN,  sizeof(struct tcp_pcb_listen), \"TCP_PCB_LISTEN\", DMEM_ATTR)\nLWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        \"TCP_SEG\", DMEM_ATTR)\n#endif /* LWIP_TCP */\n\n#if IP_REASSEMBLY\nLWIP_MEMPOOL(REASSDATA,      MEMP_NUM_REASSDATA,       sizeof(struct ip_reassdata),   \"REASSDATA\", DMEM_ATTR)\n#endif /* IP_REASSEMBLY */\n#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF\nLWIP_MEMPOOL(FRAG_PBUF,      MEMP_NUM_FRAG_PBUF,       sizeof(struct pbuf_custom_ref),\"FRAG_PBUF\", DMEM_ATTR)\n#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */\n\n#if LWIP_NETCONN\nLWIP_MEMPOOL(NETBUF,         MEMP_NUM_NETBUF,          sizeof(struct netbuf),         \"NETBUF\")\nLWIP_MEMPOOL(NETCONN,        MEMP_NUM_NETCONN,         sizeof(struct netconn),        \"NETCONN\")\n#endif /* LWIP_NETCONN */\n\n#if NO_SYS==0\nLWIP_MEMPOOL(TCPIP_MSG_API,  MEMP_NUM_TCPIP_MSG_API,   sizeof(struct tcpip_msg),      \"TCPIP_MSG_API\")\n#if !LWIP_TCPIP_CORE_LOCKING_INPUT\nLWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg),      \"TCPIP_MSG_INPKT\")\n#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */\n#endif /* NO_SYS==0 */\n\n#if ARP_QUEUEING\nLWIP_MEMPOOL(ARP_QUEUE,      MEMP_NUM_ARP_QUEUE,       sizeof(struct etharp_q_entry), \"ARP_QUEUE\", DMEM_ATTR)\n#endif /* ARP_QUEUEING */\n\n#if LWIP_IGMP\nLWIP_MEMPOOL(IGMP_GROUP,     MEMP_NUM_IGMP_GROUP,      sizeof(struct igmp_group), \"IGMP_GROUP\", DMEM_ATTR)\n#endif /* LWIP_IGMP */\n\n#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */\nLWIP_MEMPOOL(SYS_TIMEOUT,    MEMP_NUM_SYS_TIMEOUT,     sizeof(struct sys_timeo),      \"SYS_TIMEOUT\", DMEM_ATTR)\n#endif /* LWIP_TIMERS */\n\n#if LWIP_SNMP\nLWIP_MEMPOOL(SNMP_ROOTNODE,  MEMP_NUM_SNMP_ROOTNODE,   sizeof(struct mib_list_rootnode), \"SNMP_ROOTNODE\")\nLWIP_MEMPOOL(SNMP_NODE,      MEMP_NUM_SNMP_NODE,       sizeof(struct mib_list_node),     \"SNMP_NODE\")\nLWIP_MEMPOOL(SNMP_VARBIND,   MEMP_NUM_SNMP_VARBIND,    sizeof(struct snmp_varbind),      \"SNMP_VARBIND\")\nLWIP_MEMPOOL(SNMP_VALUE,     MEMP_NUM_SNMP_VALUE,      SNMP_MAX_VALUE_SIZE,              \"SNMP_VALUE\")\n#endif /* LWIP_SNMP */\n#if LWIP_DNS && LWIP_SOCKET\nLWIP_MEMPOOL(NETDB,          MEMP_NUM_NETDB,           NETDB_ELEM_SIZE,               \"NETDB\")\n#endif /* LWIP_DNS && LWIP_SOCKET */\n#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC\nLWIP_MEMPOOL(LOCALHOSTLIST,  MEMP_NUM_LOCALHOSTLIST,   LOCALHOSTLIST_ELEM_SIZE,       \"LOCALHOSTLIST\")\n#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n#if PPP_SUPPORT && PPPOE_SUPPORT\nLWIP_MEMPOOL(PPPOE_IF,      MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc),    \"PPPOE_IF\")\n#endif /* PPP_SUPPORT && PPPOE_SUPPORT */\n\n/*\n * A list of pools of pbuf's used by LWIP.\n *\n * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description)\n *     creates a pool name MEMP_pool_name. description is used in stats.c\n *     This allocates enough space for the pbuf struct and a payload.\n *     (Example: pbuf_payload_size=0 allocates only size for the struct)\n */\nLWIP_PBUF_MEMPOOL(PBUF,      MEMP_NUM_PBUF,            0,                             \"PBUF_REF/ROM\", DMEM_ATTR)\n\n/* XXX:  need to align to 4 byte as memp strcut is 4-byte long.  otherwise will crash */\n#define LWIP_MEM_ALIGN4_SIZE(size) (((size) + 4 - 1) & ~(4-1))\n\nLWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, LWIP_MEM_ALIGN4_SIZE(PBUF_POOL_BUFSIZE), \"PBUF_POOL\", DMEM_ATTR)\n\n\n/*\n * Allow for user-defined pools; this must be explicitly set in lwipopts.h\n * since the default is to NOT look for lwippools.h\n */\n#if MEMP_USE_CUSTOM_POOLS\n#include \"lwippools.h\"\n#endif /* MEMP_USE_CUSTOM_POOLS */\n\n/*\n * REQUIRED CLEANUP: Clear up so we don't get \"multiply defined\" error later\n * (#undef is ignored for something that is not defined)\n */\n#undef LWIP_MEMPOOL\n#undef LWIP_MALLOC_MEMPOOL\n#undef LWIP_MALLOC_MEMPOOL_START\n#undef LWIP_MALLOC_MEMPOOL_END\n#undef LWIP_PBUF_MEMPOOL\n"
  },
  {
    "path": "app/include/lwip/netbuf.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_NETBUF_H__\n#define __LWIP_NETBUF_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/ip_addr.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** This netbuf has dest-addr/port set */\n#define NETBUF_FLAG_DESTADDR    0x01\n/** This netbuf includes a checksum */\n#define NETBUF_FLAG_CHKSUM      0x02\n\nstruct netbuf {\n  struct pbuf *p, *ptr;\n  ip_addr_t addr;\n  u16_t port;\n#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY\n#if LWIP_CHECKSUM_ON_COPY\n  u8_t flags;\n#endif /* LWIP_CHECKSUM_ON_COPY */\n  u16_t toport_chksum;\n#if LWIP_NETBUF_RECVINFO\n  ip_addr_t toaddr;\n#endif /* LWIP_NETBUF_RECVINFO */\n#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */\n};\n\n/* Network buffer functions: */\nstruct netbuf *   netbuf_new      (void)ICACHE_FLASH_ATTR;\nvoid              netbuf_delete   (struct netbuf *buf)ICACHE_FLASH_ATTR;\nvoid *            netbuf_alloc    (struct netbuf *buf, u16_t size)ICACHE_FLASH_ATTR;\nvoid              netbuf_free     (struct netbuf *buf)ICACHE_FLASH_ATTR;\nerr_t             netbuf_ref      (struct netbuf *buf,\n                                   const void *dataptr, u16_t size)ICACHE_FLASH_ATTR;\nvoid              netbuf_chain    (struct netbuf *head,\n           struct netbuf *tail)ICACHE_FLASH_ATTR;\n\nerr_t             netbuf_data     (struct netbuf *buf,\n                                   void **dataptr, u16_t *len)ICACHE_FLASH_ATTR;\ns8_t              netbuf_next     (struct netbuf *buf)ICACHE_FLASH_ATTR;\nvoid              netbuf_first    (struct netbuf *buf)ICACHE_FLASH_ATTR;\n\n\n#define netbuf_copy_partial(buf, dataptr, len, offset) \\\n  pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))\n#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)\n#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)\n#define netbuf_len(buf)              ((buf)->p->tot_len)\n#define netbuf_fromaddr(buf)         (&((buf)->addr))\n#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr)\n#define netbuf_fromport(buf)         ((buf)->port)\n#if LWIP_NETBUF_RECVINFO\n#define netbuf_destaddr(buf)         (&((buf)->toaddr))\n#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr)\n#define netbuf_destport(buf)         (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0)\n#endif /* LWIP_NETBUF_RECVINFO */\n#if LWIP_CHECKSUM_ON_COPY\n#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \\\n                                            (buf)->toport_chksum = chksum; } while(0)\n#endif /* LWIP_CHECKSUM_ON_COPY */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_NETBUF_H__ */\n"
  },
  {
    "path": "app/include/lwip/netdb.h",
    "content": "/*\n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Simon Goldschmidt\n *\n */\n#ifndef __LWIP_NETDB_H__\n#define __LWIP_NETDB_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_DNS && LWIP_SOCKET\n\n#include <stddef.h> /* for size_t */\n\n#include \"lwip/inet.h\"\n#include \"lwip/sockets.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* some rarely used options */\n#ifndef LWIP_DNS_API_DECLARE_H_ERRNO\n#define LWIP_DNS_API_DECLARE_H_ERRNO 1\n#endif\n\n#ifndef LWIP_DNS_API_DEFINE_ERRORS\n#define LWIP_DNS_API_DEFINE_ERRORS 1\n#endif\n\n#ifndef LWIP_DNS_API_DECLARE_STRUCTS\n#define LWIP_DNS_API_DECLARE_STRUCTS 1\n#endif\n\n#if LWIP_DNS_API_DEFINE_ERRORS\n/** Errors used by the DNS API functions, h_errno can be one of them */\n#define EAI_NONAME      200\n#define EAI_SERVICE     201\n#define EAI_FAIL        202\n#define EAI_MEMORY      203\n\n#define HOST_NOT_FOUND  210\n#define NO_DATA         211\n#define NO_RECOVERY     212\n#define TRY_AGAIN       213\n#endif /* LWIP_DNS_API_DEFINE_ERRORS */\n\n#if LWIP_DNS_API_DECLARE_STRUCTS\nstruct hostent {\n    char  *h_name;      /* Official name of the host. */\n    char **h_aliases;   /* A pointer to an array of pointers to alternative host names,\n                           terminated by a null pointer. */\n    int    h_addrtype;  /* Address type. */\n    int    h_length;    /* The length, in bytes, of the address. */\n    char **h_addr_list; /* A pointer to an array of pointers to network addresses (in\n                           network byte order) for the host, terminated by a null pointer. */\n#define h_addr h_addr_list[0] /* for backward compatibility */\n};\n\nstruct addrinfo {\n    int               ai_flags;      /* Input flags. */\n    int               ai_family;     /* Address family of socket. */\n    int               ai_socktype;   /* Socket type. */\n    int               ai_protocol;   /* Protocol of socket. */\n    socklen_t         ai_addrlen;    /* Length of socket address. */\n    struct sockaddr  *ai_addr;       /* Socket address of socket. */\n    char             *ai_canonname;  /* Canonical name of service location. */\n    struct addrinfo  *ai_next;       /* Pointer to next in list. */\n};\n#endif /* LWIP_DNS_API_DECLARE_STRUCTS */\n\n#if LWIP_DNS_API_DECLARE_H_ERRNO\n/* application accessable error code set by the DNS API functions */\nextern int h_errno;\n#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/\n\nstruct hostent *lwip_gethostbyname(const char *name);\nint lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,\n                size_t buflen, struct hostent **result, int *h_errnop);\nvoid lwip_freeaddrinfo(struct addrinfo *ai);\nint lwip_getaddrinfo(const char *nodename,\n       const char *servname,\n       const struct addrinfo *hints,\n       struct addrinfo **res);\n\n#if LWIP_COMPAT_SOCKETS\n#define gethostbyname(name) lwip_gethostbyname(name)\n#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \\\n       lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)\n#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)\n#define getaddrinfo(nodname, servname, hints, res) \\\n       lwip_getaddrinfo(nodname, servname, hints, res)\n#endif /* LWIP_COMPAT_SOCKETS */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_DNS && LWIP_SOCKET */\n\n#endif /* __LWIP_NETDB_H__ */\n"
  },
  {
    "path": "app/include/lwip/netif.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_NETIF_H__\n#define __LWIP_NETIF_H__\n\n#include \"lwip/opt.h\"\n\n#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)\n\n#include \"lwip/err.h\"\n\n#include \"lwip/ip_addr.h\"\n\n#include \"lwip/def.h\"\n#include \"lwip/pbuf.h\"\n#if LWIP_DHCP\nstruct dhcp;\n#endif\n#if LWIP_AUTOIP\nstruct autoip;\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Throughout this file, IP addresses are expected to be in\n * the same byte order as in IP_PCB. */\n\n/** must be the maximum of all used hardware address lengths\n    across all types of interfaces in use */\n#define NETIF_MAX_HWADDR_LEN 6U\n\n/** Whether the network interface is 'up'. This is\n * a software flag used to control whether this network\n * interface is enabled and processes traffic.\n * It is set by the startup code (for static IP configuration) or\n * by dhcp/autoip when an address has been assigned.\n */\n#define NETIF_FLAG_UP           0x01U\n/** If set, the netif has broadcast capability.\n * Set by the netif driver in its init function. */\n#define NETIF_FLAG_BROADCAST    0x02U\n/** If set, the netif is one end of a point-to-point connection.\n * Set by the netif driver in its init function. */\n#define NETIF_FLAG_POINTTOPOINT 0x04U\n/** If set, the interface is configured using DHCP.\n * Set by the DHCP code when starting or stopping DHCP. */\n#define NETIF_FLAG_DHCP         0x08U\n/** If set, the interface has an active link\n *  (set by the network interface driver).\n * Either set by the netif driver in its init function (if the link\n * is up at that time) or at a later point once the link comes up\n * (if link detection is supported by the hardware). */\n#define NETIF_FLAG_LINK_UP      0x10U\n/** If set, the netif is an ethernet device using ARP.\n * Set by the netif driver in its init function.\n * Used to check input packet types and use of DHCP. */\n#define NETIF_FLAG_ETHARP       0x20U\n/** If set, the netif is an ethernet device. It might not use\n * ARP or TCP/IP if it is used for PPPoE only.\n */\n#define NETIF_FLAG_ETHERNET     0x40U\n/** If set, the netif has IGMP capability.\n * Set by the netif driver in its init function. */\n#define NETIF_FLAG_IGMP         0x80U\n\n/** Function prototype for netif init functions. Set up flags and output/linkoutput\n * callback functions in this function.\n *\n * @param netif The netif to initialize\n */\ntypedef err_t (*netif_init_fn)(struct netif *netif);\n/** Function prototype for netif->input functions. This function is saved as 'input'\n * callback function in the netif struct. Call it when a packet has been received.\n *\n * @param p The received packet, copied into a pbuf\n * @param inp The netif which received the packet\n */\ntypedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);\n/** Function prototype for netif->output functions. Called by lwIP when a packet\n * shall be sent. For ethernet netif, set this to 'etharp_output' and set\n * 'linkoutput'.\n *\n * @param netif The netif which shall send a packet\n * @param p The packet to send (p->payload points to IP header)\n * @param ipaddr The IP address to which the packet shall be sent\n */\ntypedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,\n       ip_addr_t *ipaddr);\n/** Function prototype for netif->linkoutput functions. Only used for ethernet\n * netifs. This function is called by ARP when a packet shall be sent.\n *\n * @param netif The netif which shall send a packet\n * @param p The packet to send (raw ethernet packet)\n */\ntypedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p);\n/** Function prototype for netif status- or link-callback functions. */\ntypedef void (*netif_status_callback_fn)(struct netif *netif);\n/** Function prototype for netif igmp_mac_filter functions */\ntypedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,\n       ip_addr_t *group, u8_t action);\n\n/*add DHCP event processing by LiuHan*/\ntypedef void (*dhcp_event_fn)(void);\n\n/** Generic data structure used for all lwIP network interfaces.\n *  The following fields should be filled in by the initialization\n *  function for the device driver: hwaddr_len, hwaddr[], mtu, flags */\nstruct netif {\n  /** pointer to next in linked list */\n  struct netif *next;\n\n  /** IP address configuration in network byte order */\n  ip_addr_t ip_addr;\n  ip_addr_t netmask;\n  ip_addr_t gw;\n\n  /** This function is called by the network device driver\n   *  to pass a packet up the TCP/IP stack. IPݰ*/\n  netif_input_fn input;\n  /** This function is called by the IP module when it wants\n   *  to send a packet on the interface. This function typically\n   *  first resolves the hardware address, then sends the packet. IPݰ*/\n  netif_output_fn output;\n  /** This function is called by the ARP module when it wants\n   *  to send a packet on the interface. This function outputs\n   *  the pbuf as-is on the link medium. ײݰ*/\n  netif_linkoutput_fn linkoutput;\n#if LWIP_NETIF_STATUS_CALLBACK\n  /** This function is called when the netif state is set to up or down\n   */\n  netif_status_callback_fn status_callback;\n#endif /* LWIP_NETIF_STATUS_CALLBACK */\n#if LWIP_NETIF_LINK_CALLBACK\n  /** This function is called when the netif link is set to up or down\n   */\n  netif_status_callback_fn link_callback;\n#endif /* LWIP_NETIF_LINK_CALLBACK */\n  /** This field can be set by the device driver and could point\n   *  to state information for the device. ֶΣָײ豸Ϣ*/\n  void *state;\n#if LWIP_DHCP\n  /** the DHCP client state information for this netif */\n  struct dhcp *dhcp;\n  struct udp_pcb *dhcps_pcb;\t//dhcps\n  dhcp_event_fn dhcp_event;\n#endif /* LWIP_DHCP */\n#if LWIP_AUTOIP\n  /** the AutoIP client state information for this netif */\n  struct autoip *autoip;\n#endif\n#if LWIP_NETIF_HOSTNAME\n  /* the hostname for this netif, NULL is a valid value */\n  char*  hostname;\n#endif /* LWIP_NETIF_HOSTNAME */\n  /** maximum transfer unit (in bytes) ýӿݰȣ1500*/\n  u16_t mtu;\n  /** number of bytes used in hwaddrýӿַ */\n  u8_t hwaddr_len;\n  /** link level hardware address of this interface ýӿַ*/\n  u8_t hwaddr[NETIF_MAX_HWADDR_LEN];\n  /** flags (see NETIF_FLAG_ above) ýӿ״ֶ̬*/\n  u8_t flags;\n  /** descriptive abbreviation ýӿڵ*/\n  char name[2];\n  /** number of this interface ýӿڵı*/\n  u8_t num;\n#if LWIP_SNMP\n  /** link type (from \"snmp_ifType\" enum from snmp.h) */\n  u8_t link_type;\n  /** (estimate) link speed */\n  u32_t link_speed;\n  /** timestamp at last change made (up/down) */\n  u32_t ts;\n  /** counters */\n  u32_t ifinoctets;\n  u32_t ifinucastpkts;\n  u32_t ifinnucastpkts;\n  u32_t ifindiscards;\n  u32_t ifoutoctets;\n  u32_t ifoutucastpkts;\n  u32_t ifoutnucastpkts;\n  u32_t ifoutdiscards;\n#endif /* LWIP_SNMP */\n#if LWIP_IGMP\n  /** This function could be called to add or delete a entry in the multicast\n      filter table of the ethernet MAC.*/\n  netif_igmp_mac_filter_fn igmp_mac_filter;\n#endif /* LWIP_IGMP */\n#if LWIP_NETIF_HWADDRHINT\n  u8_t *addr_hint;\n#endif /* LWIP_NETIF_HWADDRHINT */\n#if ENABLE_LOOPBACK\n  /* List of packets to be queued for ourselves. ָ͸Լݰpbuf*/\n  struct pbuf *loop_first;//һ\n  struct pbuf *loop_last;//һ\n#if LWIP_LOOPBACK_MAX_PBUFS\n  u16_t loop_cnt_current;\n#endif /* LWIP_LOOPBACK_MAX_PBUFS */\n#endif /* ENABLE_LOOPBACK */\n};\n\n#if LWIP_SNMP\n#define NETIF_INIT_SNMP(netif, type, speed) \\\n  /* use \"snmp_ifType\" enum from snmp.h for \"type\", snmp_ifType_ethernet_csmacd by example */ \\\n  (netif)->link_type = (type);    \\\n  /* your link speed here (units: bits per second) */  \\\n  (netif)->link_speed = (speed);  \\\n  (netif)->ts = 0;              \\\n  (netif)->ifinoctets = 0;      \\\n  (netif)->ifinucastpkts = 0;   \\\n  (netif)->ifinnucastpkts = 0;  \\\n  (netif)->ifindiscards = 0;    \\\n  (netif)->ifoutoctets = 0;     \\\n  (netif)->ifoutucastpkts = 0;  \\\n  (netif)->ifoutnucastpkts = 0; \\\n  (netif)->ifoutdiscards = 0\n#else /* LWIP_SNMP */\n#define NETIF_INIT_SNMP(netif, type, speed)\n#endif /* LWIP_SNMP */\n\n\n/** The list of network interfaces. */\nextern struct netif *netif_list;\n/** The default network interface. */\nextern struct netif *netif_default;\n\nvoid netif_init(void)ICACHE_FLASH_ATTR;\n\nstruct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,\n      ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)ICACHE_FLASH_ATTR;\n\nvoid\nnetif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,\n      ip_addr_t *gw)ICACHE_FLASH_ATTR;\nvoid netif_remove(struct netif * netif)ICACHE_FLASH_ATTR;\n\n/* Returns a network interface given its name. The name is of the form\n   \"et0\", where the first two letters are the \"name\" field in the\n   netif structure, and the digit is in the num field in the same\n   structure. */\nstruct netif *netif_find(char *name)ICACHE_FLASH_ATTR;\n\nvoid netif_set_default(struct netif *netif)ICACHE_FLASH_ATTR;\n\nvoid netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;\nvoid netif_set_netmask(struct netif *netif, ip_addr_t *netmask)ICACHE_FLASH_ATTR;\nvoid netif_set_gw(struct netif *netif, ip_addr_t *gw)ICACHE_FLASH_ATTR;\n\nvoid netif_set_up(struct netif *netif)ICACHE_FLASH_ATTR;\nvoid netif_set_down(struct netif *netif)ICACHE_FLASH_ATTR;\n/** Ask if an interface is up */\n#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0)\n\n#if LWIP_NETIF_STATUS_CALLBACK\nvoid netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)ICACHE_FLASH_ATTR;\n#endif /* LWIP_NETIF_STATUS_CALLBACK */\n\nvoid netif_set_link_up(struct netif *netif)ICACHE_FLASH_ATTR;\nvoid netif_set_link_down(struct netif *netif)ICACHE_FLASH_ATTR;\n/** Ask if a link is up */ \n#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0)\n\n#if LWIP_NETIF_LINK_CALLBACK\nvoid netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)ICACHE_FLASH_ATTR;\n#endif /* LWIP_NETIF_LINK_CALLBACK */\n\n#if LWIP_NETIF_HOSTNAME\n#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0)\n#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL)\n#endif /* LWIP_NETIF_HOSTNAME */\n\n#if LWIP_IGMP\n#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0)\n#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL)\n#endif /* LWIP_IGMP */\n\n#if ENABLE_LOOPBACK\nerr_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip)ICACHE_FLASH_ATTR;\nvoid netif_poll(struct netif *netif)ICACHE_FLASH_ATTR;\n#if !LWIP_NETIF_LOOPBACK_MULTITHREADING\nvoid netif_poll_all(void)ICACHE_FLASH_ATTR;\n#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */\n#endif /* ENABLE_LOOPBACK */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_NETIF_H__ */\n"
  },
  {
    "path": "app/include/lwip/netifapi.h",
    "content": "/*\n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n */\n \n#ifndef __LWIP_NETIFAPI_H__\n#define __LWIP_NETIFAPI_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/sys.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/dhcp.h\"\n#include \"lwip/autoip.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef void (*netifapi_void_fn)(struct netif *netif);\ntypedef err_t (*netifapi_errt_fn)(struct netif *netif);\n\nstruct netifapi_msg_msg {\n#if !LWIP_TCPIP_CORE_LOCKING\n  sys_sem_t sem;\n#endif /* !LWIP_TCPIP_CORE_LOCKING */\n  err_t err;\n  struct netif *netif;\n  union {\n    struct {\n      ip_addr_t *ipaddr;\n      ip_addr_t *netmask;\n      ip_addr_t *gw;\n      void *state;\n      netif_init_fn init;\n      netif_input_fn input;\n    } add;\n    struct {\n      netifapi_void_fn voidfunc;\n      netifapi_errt_fn errtfunc;\n    } common;\n  } msg;\n};\n\nstruct netifapi_msg {\n  void (* function)(struct netifapi_msg_msg *msg);\n  struct netifapi_msg_msg msg;\n};\n\n\n/* API for application */\nerr_t netifapi_netif_add       ( struct netif *netif,\n                                 ip_addr_t *ipaddr,\n                                 ip_addr_t *netmask,\n                                 ip_addr_t *gw,\n                                 void *state,\n                                 netif_init_fn init,\n                                 netif_input_fn input);\n\nerr_t netifapi_netif_set_addr  ( struct netif *netif,\n                                 ip_addr_t *ipaddr,\n                                 ip_addr_t *netmask,\n                                 ip_addr_t *gw );\n\nerr_t netifapi_netif_common    ( struct netif *netif,\n                                 netifapi_void_fn voidfunc,\n                                 netifapi_errt_fn errtfunc);\n\n#define netifapi_netif_remove(n)      netifapi_netif_common(n, netif_remove, NULL)\n#define netifapi_netif_set_up(n)      netifapi_netif_common(n, netif_set_up, NULL)\n#define netifapi_netif_set_down(n)    netifapi_netif_common(n, netif_set_down, NULL)\n#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL)\n#define netifapi_dhcp_start(n)        netifapi_netif_common(n, NULL, dhcp_start)\n#define netifapi_dhcp_stop(n)         netifapi_netif_common(n, dhcp_stop, NULL)\n#define netifapi_autoip_start(n)      netifapi_netif_common(n, NULL, autoip_start)\n#define netifapi_autoip_stop(n)       netifapi_netif_common(n, NULL, autoip_stop)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_NETIF_API */\n\n#endif /* __LWIP_NETIFAPI_H__ */\n"
  },
  {
    "path": "app/include/lwip/opt.h",
    "content": "/**\n * @file\n *\n * lwIP Options Configuration\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_OPT_H__\n#define __LWIP_OPT_H__\n\n/*\n * Include user defined options first. Anything not defined in these files\n * will be set to standard values. Override anything you dont like!\n */\n#include \"lwipopts.h\"\n#include \"lwip/debug.h\"\n\n/*\n   -----------------------------------------------\n   ---------- Platform specific locking ----------\n   -----------------------------------------------\n*/\n\n/**\n * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain\n * critical regions during buffer allocation, deallocation and memory\n * allocation and deallocation.\n */\n#ifndef SYS_LIGHTWEIGHT_PROT\n#define SYS_LIGHTWEIGHT_PROT            0\n#endif\n\n/** \n * NO_SYS==1: Provides VERY minimal functionality. Otherwise,\n * use lwIP facilities.\n */\n#ifndef NO_SYS\n#define NO_SYS                          1\n#endif\n\n/**\n * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1\n * Mainly for compatibility to old versions.\n */\n#ifndef NO_SYS_NO_TIMERS\n#define NO_SYS_NO_TIMERS                1\n#endif\n\n/**\n * MEMCPY: override this if you have a faster implementation at hand than the\n * one included in your C library\n */\n#ifndef MEMCPY\n#define MEMCPY(dst,src,len)             memcpy(dst,src,len)\n#endif\n\n/**\n * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a\n * call to memcpy() if the length is known at compile time and is small.\n */\n#ifndef SMEMCPY\n#define SMEMCPY(dst,src,len)            memcpy(dst,src,len)\n#endif\n\n/*\n   ------------------------------------\n   ---------- Memory options ----------\n   ------------------------------------\n*/\n/**\n * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library\n * instead of the lwip internal allocator. Can save code size if you\n * already use it.\n */\n#ifndef MEM_LIBC_MALLOC\n#define MEM_LIBC_MALLOC                 0\n#endif\n\n/**\n* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator.\n* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution\n* speed and usage from interrupts!\n*/\n#ifndef MEMP_MEM_MALLOC\n#define MEMP_MEM_MALLOC                 0\n#endif\n\n/**\n * MEM_ALIGNMENT: should be set to the alignment of the CPU\n *    4 byte alignment -> #define MEM_ALIGNMENT 4\n *    2 byte alignment -> #define MEM_ALIGNMENT 2\n */\n#ifndef MEM_ALIGNMENT\n#define MEM_ALIGNMENT                   1\n#endif\n\n/**\n * MEM_SIZE: the size of the heap memory. If the application will send\n * a lot of data that needs to be copied, this should be set high.\n */\n#ifndef MEM_SIZE\n#define MEM_SIZE                        1600\n#endif\n\n/**\n * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array.\n * This can be used to individually change the location of each pool.\n * Default is one big array for all pools\n */\n#ifndef MEMP_SEPARATE_POOLS\n#define MEMP_SEPARATE_POOLS             0\n#endif\n\n/**\n * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable\n * amount of bytes before and after each memp element in every pool and fills\n * it with a prominent default value.\n *    MEMP_OVERFLOW_CHECK == 0 no checking\n *    MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed\n *    MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time\n *      memp_malloc() or memp_free() is called (useful but slow!)\n */\n#ifndef MEMP_OVERFLOW_CHECK\n#define MEMP_OVERFLOW_CHECK             0\n#endif\n\n/**\n * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make\n * sure that there are no cycles in the linked lists.\n */\n#ifndef MEMP_SANITY_CHECK\n#define MEMP_SANITY_CHECK               0\n#endif\n\n/**\n * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set\n * of memory pools of various sizes. When mem_malloc is called, an element of\n * the smallest pool that can provide the length needed is returned.\n * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled.\n */\n#ifndef MEM_USE_POOLS\n#define MEM_USE_POOLS                   0\n#endif\n\n/**\n * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next\n * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more\n * reliable. */\n#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL\n#define MEM_USE_POOLS_TRY_BIGGER_POOL   0\n#endif\n\n/**\n * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h\n * that defines additional pools beyond the \"standard\" ones required\n * by lwIP. If you set this to 1, you must have lwippools.h in your \n * inlude path somewhere. \n */\n#ifndef MEMP_USE_CUSTOM_POOLS\n#define MEMP_USE_CUSTOM_POOLS           0\n#endif\n\n/**\n * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from\n * interrupt context (or another context that doesn't allow waiting for a\n * semaphore).\n * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT,\n * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs\n * with each loop so that mem_free can run.\n *\n * ATTENTION: As you can see from the above description, this leads to dis-/\n * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc\n * can need longer.\n *\n * If you don't want that, at least for NO_SYS=0, you can still use the following\n * functions to enqueue a deallocation call which then runs in the tcpip_thread\n * context:\n * - pbuf_free_callback(p);\n * - mem_free_callback(m);\n */\n#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0\n#endif\n\n/*\n   ------------------------------------------------\n   ---------- Internal Memory Pool Sizes ----------\n   ------------------------------------------------\n*/\n/**\n * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF).\n * If the application sends a lot of data out of ROM (or other static memory),\n * this should be set high.\n */\n#ifndef MEMP_NUM_PBUF\n#define MEMP_NUM_PBUF                   16\n#endif\n\n/**\n * MEMP_NUM_RAW_PCB: Number of raw connection PCBs\n * (requires the LWIP_RAW option)\n */\n#ifndef MEMP_NUM_RAW_PCB\n#define MEMP_NUM_RAW_PCB                4\n#endif\n\n/**\n * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One\n * per active UDP \"connection\".\n * (requires the LWIP_UDP option)\n */\n#ifndef MEMP_NUM_UDP_PCB\n#define MEMP_NUM_UDP_PCB                4\n#endif\n\n/**\n * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections.\n * (requires the LWIP_TCP option)\n */\n#ifndef MEMP_NUM_TCP_PCB\n#define MEMP_NUM_TCP_PCB                5\n#endif\n\n/**\n * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections.\n * (requires the LWIP_TCP option)\n */\n#ifndef MEMP_NUM_TCP_PCB_LISTEN\n#define MEMP_NUM_TCP_PCB_LISTEN         8\n#endif\n\n/**\n * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.\n * (requires the LWIP_TCP option)\n */\n#ifndef MEMP_NUM_TCP_SEG\n#define MEMP_NUM_TCP_SEG                16\n#endif\n\n/**\n * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for\n * reassembly (whole packets, not fragments!)\n */\n#ifndef MEMP_NUM_REASSDATA\n#define MEMP_NUM_REASSDATA              5\n#endif\n\n/**\n * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent\n * (fragments, not whole packets!).\n * This is only used with IP_FRAG_USES_STATIC_BUF==0 and\n * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs\n * where the packet is not yet sent when netif->output returns.\n */\n#ifndef MEMP_NUM_FRAG_PBUF\n#define MEMP_NUM_FRAG_PBUF              15\n#endif\n\n/**\n * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing\n * packets (pbufs) that are waiting for an ARP request (to resolve\n * their destination address) to finish.\n * (requires the ARP_QUEUEING option)\n */\n#ifndef MEMP_NUM_ARP_QUEUE\n#define MEMP_NUM_ARP_QUEUE              30\n#endif\n\n/**\n * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces\n * can be members et the same time (one per netif - allsystems group -, plus one\n * per netif membership).\n * (requires the LWIP_IGMP option)\n */\n#ifndef MEMP_NUM_IGMP_GROUP\n#define MEMP_NUM_IGMP_GROUP             8\n#endif\n\n/**\n * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.\n * (requires NO_SYS==0)\n */\n#ifndef MEMP_NUM_SYS_TIMEOUT\n#define MEMP_NUM_SYS_TIMEOUT            3\n#endif\n\n/**\n * MEMP_NUM_NETBUF: the number of struct netbufs.\n * (only needed if you use the sequential API, like api_lib.c)\n */\n#ifndef MEMP_NUM_NETBUF\n#define MEMP_NUM_NETBUF                 2\n#endif\n\n/**\n * MEMP_NUM_NETCONN: the number of struct netconns.\n * (only needed if you use the sequential API, like api_lib.c)\n */\n#ifndef MEMP_NUM_NETCONN\n#define MEMP_NUM_NETCONN                4\n#endif\n\n/**\n * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used\n * for callback/timeout API communication. \n * (only needed if you use tcpip.c)\n */\n#ifndef MEMP_NUM_TCPIP_MSG_API\n#define MEMP_NUM_TCPIP_MSG_API          8\n#endif\n\n/**\n * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used\n * for incoming packets. \n * (only needed if you use tcpip.c)\n */\n#ifndef MEMP_NUM_TCPIP_MSG_INPKT\n#define MEMP_NUM_TCPIP_MSG_INPKT        8\n#endif\n\n/**\n * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree.\n */\n#ifndef MEMP_NUM_SNMP_NODE\n#define MEMP_NUM_SNMP_NODE              50\n#endif\n\n/**\n * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree.\n * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least!\n */\n#ifndef MEMP_NUM_SNMP_ROOTNODE\n#define MEMP_NUM_SNMP_ROOTNODE          30\n#endif\n\n/**\n * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to\n * be changed normally) - 2 of these are used per request (1 for input,\n * 1 for output)\n */\n#ifndef MEMP_NUM_SNMP_VARBIND\n#define MEMP_NUM_SNMP_VARBIND           2\n#endif\n\n/**\n * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used\n * (does not have to be changed normally) - 3 of these are used per request\n * (1 for the value read and 2 for OIDs - input and output)\n */\n#ifndef MEMP_NUM_SNMP_VALUE\n#define MEMP_NUM_SNMP_VALUE             3\n#endif\n\n/**\n * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls\n * (before freeing the corresponding memory using lwip_freeaddrinfo()).\n */\n#ifndef MEMP_NUM_NETDB\n#define MEMP_NUM_NETDB                  1\n#endif\n\n/**\n * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list\n * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1.\n */\n#ifndef MEMP_NUM_LOCALHOSTLIST\n#define MEMP_NUM_LOCALHOSTLIST          1\n#endif\n\n/**\n * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE\n * interfaces (only used with PPPOE_SUPPORT==1)\n */\n#ifndef MEMP_NUM_PPPOE_INTERFACES\n#define MEMP_NUM_PPPOE_INTERFACES       1\n#endif\n\n/**\n * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. \n */\n#ifndef PBUF_POOL_SIZE\n#define PBUF_POOL_SIZE                  16\n#endif\n\n/*\n   ---------------------------------\n   ---------- ARP options ----------\n   ---------------------------------\n*/\n/**\n * LWIP_ARP==1: Enable ARP functionality.\n */\n#ifndef LWIP_ARP\n#define LWIP_ARP                        1\n#endif\n\n/**\n * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached.\n */\n#ifndef ARP_TABLE_SIZE\n#define ARP_TABLE_SIZE                  10\n#endif\n\n/**\n * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address\n * resolution. By default, only the most recent packet is queued per IP address.\n * This is sufficient for most protocols and mainly reduces TCP connection\n * startup time. Set this to 1 if you know your application sends more than one\n * packet in a row to an IP address that is not in the ARP cache.\n */\n#ifndef ARP_QUEUEING\n#define ARP_QUEUEING                    0\n#endif\n\n/**\n * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be\n * updated with the source MAC and IP addresses supplied in the packet.\n * You may want to disable this if you do not trust LAN peers to have the\n * correct addresses, or as a limited approach to attempt to handle\n * spoofing. If disabled, lwIP will need to make a new ARP request if\n * the peer is not already in the ARP table, adding a little latency.\n * The peer *is* in the ARP table if it requested our address before.\n * Also notice that this slows down input processing of every IP packet!\n */\n#ifndef ETHARP_TRUST_IP_MAC\n#define ETHARP_TRUST_IP_MAC             0\n#endif\n\n/**\n * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header.\n * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check.\n * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted.\n * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted.\n */\n#ifndef ETHARP_SUPPORT_VLAN\n#define ETHARP_SUPPORT_VLAN             0\n#endif\n\n/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP\n * might be disabled\n */\n#ifndef LWIP_ETHERNET\n#define LWIP_ETHERNET                   (LWIP_ARP || PPPOE_SUPPORT)\n#endif\n\n/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure\n * alignment of payload after that header. Since the header is 14 bytes long,\n * without this padding e.g. addresses in the IP header will not be aligned\n * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms.\n */\n#ifndef ETH_PAD_SIZE\n#define ETH_PAD_SIZE                    0\n#endif\n\n/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table\n * entries (using etharp_add_static_entry/etharp_remove_static_entry).\n */\n#ifndef ETHARP_SUPPORT_STATIC_ENTRIES\n#define ETHARP_SUPPORT_STATIC_ENTRIES   0\n#endif\n\n\n/*\n   --------------------------------\n   ---------- IP options ----------\n   --------------------------------\n*/\n/**\n * IP_FORWARD==1: Enables the ability to forward IP packets across network\n * interfaces. If you are going to run lwIP on a device with only one network\n * interface, define this to 0.\n */\n#ifndef IP_FORWARD\n#define IP_FORWARD                      0\n#endif\n\n/**\n * IP_OPTIONS_ALLOWED: Defines the behavior for IP options.\n *      IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped.\n *      IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed).\n */\n#ifndef IP_OPTIONS_ALLOWED\n#define IP_OPTIONS_ALLOWED              1\n#endif\n\n/**\n * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that\n * this option does not affect outgoing packet sizes, which can be controlled\n * via IP_FRAG.\n */\n#ifndef IP_REASSEMBLY\n#define IP_REASSEMBLY                   0\n#endif\n\n/**\n * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note\n * that this option does not affect incoming packet sizes, which can be\n * controlled via IP_REASSEMBLY.\n */\n#ifndef IP_FRAG\n#define IP_FRAG                         1\n#endif\n\n/**\n * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)\n * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived\n * in this time, the whole packet is discarded.\n */\n#ifndef IP_REASS_MAXAGE\n#define IP_REASS_MAXAGE                 3\n#endif\n\n/**\n * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled.\n * Since the received pbufs are enqueued, be sure to configure\n * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive\n * packets even if the maximum amount of fragments is enqueued for reassembly!\n */\n#ifndef IP_REASS_MAX_PBUFS\n#define IP_REASS_MAX_PBUFS              10\n#endif\n\n/**\n * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP\n * fragmentation. Otherwise pbufs are allocated and reference the original\n * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1,\n * new PBUF_RAM pbufs are used for fragments).\n * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs!\n */\n#ifndef IP_FRAG_USES_STATIC_BUF\n#define IP_FRAG_USES_STATIC_BUF         0\n#endif\n\n/**\n * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer\n * (requires IP_FRAG_USES_STATIC_BUF==1)\n */\n#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU)\n#define IP_FRAG_MAX_MTU                 1500\n#endif\n\n/**\n * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers.\n */\n#ifndef IP_DEFAULT_TTL\n#define IP_DEFAULT_TTL                  255\n#endif\n\n/**\n * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast\n * filter per pcb on udp and raw send operations. To enable broadcast filter\n * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1.\n */\n#ifndef IP_SOF_BROADCAST\n#define IP_SOF_BROADCAST                0\n#endif\n\n/**\n * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast\n * filter on recv operations.\n */\n#ifndef IP_SOF_BROADCAST_RECV\n#define IP_SOF_BROADCAST_RECV           0\n#endif\n\n/*\n   ----------------------------------\n   ---------- ICMP options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_ICMP==1: Enable ICMP module inside the IP stack.\n * Be careful, disable that make your product non-compliant to RFC1122\n */\n#ifndef LWIP_ICMP\n#define LWIP_ICMP                       1\n#endif\n\n/**\n * ICMP_TTL: Default value for Time-To-Live used by ICMP packets.\n */\n#ifndef ICMP_TTL\n#define ICMP_TTL                       (IP_DEFAULT_TTL)\n#endif\n\n/**\n * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only)\n */\n#ifndef LWIP_BROADCAST_PING\n#define LWIP_BROADCAST_PING             0\n#endif\n\n/**\n * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only)\n */\n#ifndef LWIP_MULTICAST_PING\n#define LWIP_MULTICAST_PING             0\n#endif\n\n/*\n   ---------------------------------\n   ---------- RAW options ----------\n   ---------------------------------\n*/\n/**\n * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.\n */\n#ifndef LWIP_RAW\n#define LWIP_RAW                        1\n#endif\n\n/**\n * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.\n */\n#ifndef RAW_TTL\n#define RAW_TTL                        (IP_DEFAULT_TTL)\n#endif\n\n/*\n   ----------------------------------\n   ---------- DHCP options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_DHCP==1: Enable DHCP module.\n */\n#ifndef LWIP_DHCP\n#define LWIP_DHCP                       0\n#endif\n\n/**\n * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address.\n */\n#ifndef DHCP_DOES_ARP_CHECK\n#define DHCP_DOES_ARP_CHECK             ((LWIP_DHCP) && (LWIP_ARP))\n#endif\n\n/*\n   ------------------------------------\n   ---------- AUTOIP options ----------\n   ------------------------------------\n*/\n/**\n * LWIP_AUTOIP==1: Enable AUTOIP module.\n */\n#ifndef LWIP_AUTOIP\n#define LWIP_AUTOIP                     0\n#endif\n\n/**\n * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on\n * the same interface at the same time.\n */\n#ifndef LWIP_DHCP_AUTOIP_COOP\n#define LWIP_DHCP_AUTOIP_COOP           0\n#endif\n\n/**\n * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes\n * that should be sent before falling back on AUTOIP. This can be set\n * as low as 1 to get an AutoIP address very quickly, but you should\n * be prepared to handle a changing IP address when DHCP overrides\n * AutoIP.\n */\n#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES\n#define LWIP_DHCP_AUTOIP_COOP_TRIES     9\n#endif\n\n/*\n   ----------------------------------\n   ---------- SNMP options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP\n * transport.\n */\n#ifndef LWIP_SNMP\n#define LWIP_SNMP                       0\n#endif\n\n/**\n * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will\n * allow. At least one request buffer is required.\n * Does not have to be changed unless external MIBs answer request asynchronously\n */\n#ifndef SNMP_CONCURRENT_REQUESTS\n#define SNMP_CONCURRENT_REQUESTS        1\n#endif\n\n/**\n * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap\n * destination is required\n */\n#ifndef SNMP_TRAP_DESTINATIONS\n#define SNMP_TRAP_DESTINATIONS          1\n#endif\n\n/**\n * SNMP_PRIVATE_MIB: \n * When using a private MIB, you have to create a file 'private_mib.h' that contains\n * a 'struct mib_array_node mib_private' which contains your MIB.\n */\n#ifndef SNMP_PRIVATE_MIB\n#define SNMP_PRIVATE_MIB                0\n#endif\n\n/**\n * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not\n * a safe action and disabled when SNMP_SAFE_REQUESTS = 1).\n * Unsafe requests are disabled by default!\n */\n#ifndef SNMP_SAFE_REQUESTS\n#define SNMP_SAFE_REQUESTS              1\n#endif\n\n/**\n * The maximum length of strings used. This affects the size of\n * MEMP_SNMP_VALUE elements.\n */\n#ifndef SNMP_MAX_OCTET_STRING_LEN\n#define SNMP_MAX_OCTET_STRING_LEN       127\n#endif\n\n/**\n * The maximum depth of the SNMP tree.\n * With private MIBs enabled, this depends on your MIB!\n * This affects the size of MEMP_SNMP_VALUE elements.\n */\n#ifndef SNMP_MAX_TREE_DEPTH\n#define SNMP_MAX_TREE_DEPTH             15\n#endif\n\n/**\n * The size of the MEMP_SNMP_VALUE elements, normally calculated from\n * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH.\n */\n#ifndef SNMP_MAX_VALUE_SIZE\n#define SNMP_MAX_VALUE_SIZE             LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH))\n#endif\n\n/*\n   ----------------------------------\n   ---------- IGMP options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_IGMP==1: Turn on IGMP module. \n */\n#ifndef LWIP_IGMP\n#define LWIP_IGMP                       0\n#endif\n\n/*\n   ----------------------------------\n   ---------- DNS options -----------\n   ----------------------------------\n*/\n/**\n * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS\n * transport.\n */\n#ifndef LWIP_DNS\n#define LWIP_DNS                        0\n#endif\n\n/** DNS maximum number of entries to maintain locally. */\n#ifndef DNS_TABLE_SIZE\n#define DNS_TABLE_SIZE                  4\n#endif\n\n/** DNS maximum host name length supported in the name table. */\n#ifndef DNS_MAX_NAME_LENGTH\n#define DNS_MAX_NAME_LENGTH             256\n#endif\n\n/** The maximum of DNS servers */\n#ifndef DNS_MAX_SERVERS\n#define DNS_MAX_SERVERS                 2\n#endif\n\n/** DNS do a name checking between the query and the response. */\n#ifndef DNS_DOES_NAME_CHECK\n#define DNS_DOES_NAME_CHECK             1\n#endif\n\n/** DNS message max. size. Default value is RFC compliant. */\n#ifndef DNS_MSG_SIZE\n#define DNS_MSG_SIZE                    512\n#endif\n\n/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled,\n *  you have to define\n *    #define DNS_LOCAL_HOSTLIST_INIT {{\"host1\", 0x123}, {\"host2\", 0x234}}\n *  (an array of structs name/address, where address is an u32_t in network\n *  byte order).\n *\n *  Instead, you can also use an external function:\n *  #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name)\n *  that returns the IP address or INADDR_NONE if not found.\n */\n#ifndef DNS_LOCAL_HOSTLIST\n#define DNS_LOCAL_HOSTLIST              0\n#endif /* DNS_LOCAL_HOSTLIST */\n\n/** If this is turned on, the local host-list can be dynamically changed\n *  at runtime. */\n#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC\n#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC   0\n#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n\n/*\n   ---------------------------------\n   ---------- UDP options ----------\n   ---------------------------------\n*/\n/**\n * LWIP_UDP==1: Turn on UDP.\n */\n#ifndef LWIP_UDP\n#define LWIP_UDP                        1\n#endif\n\n/**\n * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP)\n */\n#ifndef LWIP_UDPLITE\n#define LWIP_UDPLITE                    0\n#endif\n\n/**\n * UDP_TTL: Default Time-To-Live value.\n */\n#ifndef UDP_TTL\n#define UDP_TTL                         (IP_DEFAULT_TTL)\n#endif\n\n/**\n * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf.\n */\n#ifndef LWIP_NETBUF_RECVINFO\n#define LWIP_NETBUF_RECVINFO            0\n#endif\n\n/*\n   ---------------------------------\n   ---------- TCP options ----------\n   ---------------------------------\n*/\n/**\n * LWIP_TCP==1: Turn on TCP.\n */\n#ifndef LWIP_TCP\n#define LWIP_TCP                        1\n#endif\n\n/**\n * TCP_TTL: Default Time-To-Live value.\n */\n#ifndef TCP_TTL\n#define TCP_TTL                         (IP_DEFAULT_TTL)\n#endif\n\n/**\n * TCP_WND: The size of a TCP window.  This must be at least \n * (2 * TCP_MSS) for things to work well\n */\n#ifndef TCP_WND\n#define TCP_WND                         (4 * TCP_MSS)\n#endif \n\n/**\n * TCP_MAXRTX: Maximum number of retransmissions of data segments.\n */\n#ifndef TCP_MAXRTX\n#define TCP_MAXRTX                      12\n#endif\n\n/**\n * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.\n */\n#ifndef TCP_SYNMAXRTX\n#define TCP_SYNMAXRTX                   6\n#endif\n\n/**\n * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order.\n * Define to 0 if your device is low on memory.\n */\n#ifndef TCP_QUEUE_OOSEQ\n#define TCP_QUEUE_OOSEQ                 (LWIP_TCP)\n#endif\n\n/**\n * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,\n * you might want to increase this.)\n * For the receive side, this MSS is advertised to the remote side\n * when opening a connection. For the transmit size, this MSS sets\n * an upper limit on the MSS advertised by the remote host.\n */\n#ifndef TCP_MSS\n#define TCP_MSS                         536\n#endif\n\n/**\n * TCP_CALCULATE_EFF_SEND_MSS: \"The maximum size of a segment that TCP really\n * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which\n * reflects the available reassembly buffer size at the remote host) and the\n * largest size permitted by the IP layer\" (RFC 1122)\n * Setting this to 1 enables code that checks TCP_MSS against the MTU of the\n * netif used for a connection and limits the MSS if it would be too big otherwise.\n */\n#ifndef TCP_CALCULATE_EFF_SEND_MSS\n#define TCP_CALCULATE_EFF_SEND_MSS      1\n#endif\n\n\n/**\n * TCP_SND_BUF: TCP sender buffer space (bytes). \n */\n#ifndef TCP_SND_BUF\n#define TCP_SND_BUF                     256\n#endif\n\n/**\n * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least\n * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.\n */\n#ifndef TCP_SND_QUEUELEN\n#define TCP_SND_QUEUELEN                ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))\n#endif\n\n/**\n * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than\n * TCP_SND_BUF. It is the amount of space which must be available in the\n * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT).\n */\n#ifndef TCP_SNDLOWAT\n#define TCP_SNDLOWAT                    ((TCP_SND_BUF)/2)\n#endif\n\n/**\n * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater\n * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below\n * this number, select returns writable (combined with TCP_SNDLOWAT).\n */\n#ifndef TCP_SNDQUEUELOWAT\n#define TCP_SNDQUEUELOWAT               ((TCP_SND_QUEUELEN)/2)\n#endif\n\n/**\n * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.\n */\n#ifndef TCP_LISTEN_BACKLOG\n#define TCP_LISTEN_BACKLOG              0\n#endif\n\n/**\n * The maximum allowed backlog for TCP listen netconns.\n * This backlog is used unless another is explicitly specified.\n * 0xff is the maximum (u8_t).\n */\n#ifndef TCP_DEFAULT_LISTEN_BACKLOG\n#define TCP_DEFAULT_LISTEN_BACKLOG      0xff\n#endif\n\n/**\n * TCP_OVERSIZE: The maximum number of bytes that tcp_write may\n * allocate ahead of time in an attempt to create shorter pbuf chains\n * for transmission. The meaningful range is 0 to TCP_MSS. Some\n * suggested values are:\n *\n * 0:         Disable oversized allocation. Each tcp_write() allocates a new\n              pbuf (old behaviour).\n * 1:         Allocate size-aligned pbufs with minimal excess. Use this if your\n *            scatter-gather DMA requires aligned fragments.\n * 128:       Limit the pbuf/memory overhead to 20%.\n * TCP_MSS:   Try to create unfragmented TCP packets.\n * TCP_MSS/4: Try to create 4 fragments or less per TCP packet.\n */\n#ifndef TCP_OVERSIZE\n#define TCP_OVERSIZE                    TCP_MSS\n#endif\n\n/**\n * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option.\n */\n#ifndef LWIP_TCP_TIMESTAMPS\n#define LWIP_TCP_TIMESTAMPS             0\n#endif\n\n/**\n * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an\n * explicit window update\n */\n#ifndef TCP_WND_UPDATE_THRESHOLD\n#define TCP_WND_UPDATE_THRESHOLD   (TCP_WND / 4)\n#endif\n\n/**\n * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1.\n *     LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all\n *         events (accept, sent, etc) that happen in the system.\n *     LWIP_CALLBACK_API==1: The PCB callback function is called directly\n *         for the event.\n */\n//#ifndef LWIP_EVENT_API\n//#define LWIP_EVENT_API                  0\n//#define LWIP_CALLBACK_API               1\n//#else \n//#define LWIP_EVENT_API                  1\n//#define LWIP_CALLBACK_API               0\n//#endif\n\n\n/*\n   ----------------------------------\n   ---------- Pbuf options ----------\n   ----------------------------------\n*/\n/**\n * PBUF_LINK_HLEN: the number of bytes that should be allocated for a\n * link level header. The default is 14, the standard value for\n * Ethernet.\n */\n#ifndef PBUF_LINK_HLEN\n#define PBUF_LINK_HLEN                  (14 + ETH_PAD_SIZE)\n#endif\n\n/**\n * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is\n * designed to accomodate single full size TCP frame in one pbuf, including\n * TCP_MSS, IP header, and link header.\n */\n#ifndef PBUF_POOL_BUFSIZE\n#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)\n#endif\n\n/*\n   ------------------------------------------------\n   ---------- Network Interfaces options ----------\n   ------------------------------------------------\n*/\n/**\n * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname\n * field.\n */\n#ifndef LWIP_NETIF_HOSTNAME\n#define LWIP_NETIF_HOSTNAME             0\n#endif\n\n/**\n * LWIP_NETIF_API==1: Support netif api (in netifapi.c)\n */\n#ifndef LWIP_NETIF_API\n#define LWIP_NETIF_API                  0\n#endif\n\n/**\n * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface\n * changes its up/down status (i.e., due to DHCP IP acquistion)\n */\n#ifndef LWIP_NETIF_STATUS_CALLBACK\n#define LWIP_NETIF_STATUS_CALLBACK      0\n#endif\n\n/**\n * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface\n * whenever the link changes (i.e., link down)\n */\n#ifndef LWIP_NETIF_LINK_CALLBACK\n#define LWIP_NETIF_LINK_CALLBACK        0\n#endif\n\n/**\n * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table\n * indices) in struct netif. TCP and UDP can make use of this to prevent\n * scanning the ARP table for every sent packet. While this is faster for big\n * ARP tables or many concurrent connections, it might be counterproductive\n * if you have a tiny ARP table or if there never are concurrent connections.\n */\n#ifndef LWIP_NETIF_HWADDRHINT\n#define LWIP_NETIF_HWADDRHINT           0\n#endif\n\n/**\n * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP\n * address equal to the netif IP address, looping them back up the stack.\n */\n#ifndef LWIP_NETIF_LOOPBACK\n#define LWIP_NETIF_LOOPBACK             1\n#endif\n\n/**\n * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback\n * sending for each netif (0 = disabled)\n */\n#ifndef LWIP_LOOPBACK_MAX_PBUFS\n#define LWIP_LOOPBACK_MAX_PBUFS         0\n#endif\n\n/**\n * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in\n * the system, as netifs must change how they behave depending on this setting\n * for the LWIP_NETIF_LOOPBACK option to work.\n * Setting this is needed to avoid reentering non-reentrant functions like\n * tcp_input().\n *    LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a\n *       multithreaded environment like tcpip.c. In this case, netif->input()\n *       is called directly.\n *    LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.\n *       The packets are put on a list and netif_poll() must be called in\n *       the main application loop.\n */\n#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING\n#define LWIP_NETIF_LOOPBACK_MULTITHREADING    (!NO_SYS)\n#endif\n\n/**\n * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data\n * to be sent into one single pbuf. This is for compatibility with DMA-enabled\n * MACs that do not support scatter-gather.\n * Beware that this might involve CPU-memcpy before transmitting that would not\n * be needed without this flag! Use this only if you need to!\n *\n * @todo: TCP and IP-frag do not work with this, yet:\n */\n#ifndef LWIP_NETIF_TX_SINGLE_PBUF\n#define LWIP_NETIF_TX_SINGLE_PBUF             0\n#endif /* LWIP_NETIF_TX_SINGLE_PBUF */\n\n/*\n   ------------------------------------\n   ---------- LOOPIF options ----------\n   ------------------------------------\n*/\n/**\n * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c\n */\n#ifndef LWIP_HAVE_LOOPIF\n#define LWIP_HAVE_LOOPIF                1\n#endif\n\n/*\n   ------------------------------------\n   ---------- SLIPIF options ----------\n   ------------------------------------\n*/\n/**\n * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c\n */\n#ifndef LWIP_HAVE_SLIPIF\n#define LWIP_HAVE_SLIPIF                0\n#endif\n\n/*\n   ------------------------------------\n   ---------- Thread options ----------\n   ------------------------------------\n*/\n/**\n * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread.\n */\n#ifndef TCPIP_THREAD_NAME\n#define TCPIP_THREAD_NAME              \"tcpip_thread\"\n#endif\n\n/**\n * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread.\n * The stack size value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef TCPIP_THREAD_STACKSIZE\n#define TCPIP_THREAD_STACKSIZE          0\n#endif\n\n/**\n * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread.\n * The priority value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef TCPIP_THREAD_PRIO\n#define TCPIP_THREAD_PRIO               1\n#endif\n\n/**\n * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages\n * The queue size value itself is platform-dependent, but is passed to\n * sys_mbox_new() when tcpip_init is called.\n */\n#ifndef TCPIP_MBOX_SIZE\n#define TCPIP_MBOX_SIZE                 0\n#endif\n\n/**\n * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread.\n */\n#ifndef SLIPIF_THREAD_NAME\n#define SLIPIF_THREAD_NAME             \"slipif_loop\"\n#endif\n\n/**\n * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread.\n * The stack size value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef SLIPIF_THREAD_STACKSIZE\n#define SLIPIF_THREAD_STACKSIZE         0\n#endif\n\n/**\n * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread.\n * The priority value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef SLIPIF_THREAD_PRIO\n#define SLIPIF_THREAD_PRIO              1\n#endif\n\n/**\n * PPP_THREAD_NAME: The name assigned to the pppInputThread.\n */\n#ifndef PPP_THREAD_NAME\n#define PPP_THREAD_NAME                \"pppInputThread\"\n#endif\n\n/**\n * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread.\n * The stack size value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef PPP_THREAD_STACKSIZE\n#define PPP_THREAD_STACKSIZE            0\n#endif\n\n/**\n * PPP_THREAD_PRIO: The priority assigned to the pppInputThread.\n * The priority value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef PPP_THREAD_PRIO\n#define PPP_THREAD_PRIO                 1\n#endif\n\n/**\n * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread.\n */\n#ifndef DEFAULT_THREAD_NAME\n#define DEFAULT_THREAD_NAME            \"lwIP\"\n#endif\n\n/**\n * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread.\n * The stack size value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef DEFAULT_THREAD_STACKSIZE\n#define DEFAULT_THREAD_STACKSIZE        0\n#endif\n\n/**\n * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread.\n * The priority value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef DEFAULT_THREAD_PRIO\n#define DEFAULT_THREAD_PRIO             1\n#endif\n\n/**\n * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\n * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed\n * to sys_mbox_new() when the recvmbox is created.\n */\n#ifndef DEFAULT_RAW_RECVMBOX_SIZE\n#define DEFAULT_RAW_RECVMBOX_SIZE       0\n#endif\n\n/**\n * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\n * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed\n * to sys_mbox_new() when the recvmbox is created.\n */\n#ifndef DEFAULT_UDP_RECVMBOX_SIZE\n#define DEFAULT_UDP_RECVMBOX_SIZE       0\n#endif\n\n/**\n * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\n * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed\n * to sys_mbox_new() when the recvmbox is created.\n */\n#ifndef DEFAULT_TCP_RECVMBOX_SIZE\n#define DEFAULT_TCP_RECVMBOX_SIZE       0\n#endif\n\n/**\n * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections.\n * The queue size value itself is platform-dependent, but is passed to\n * sys_mbox_new() when the acceptmbox is created.\n */\n#ifndef DEFAULT_ACCEPTMBOX_SIZE\n#define DEFAULT_ACCEPTMBOX_SIZE         0\n#endif\n\n/*\n   ----------------------------------------------\n   ---------- Sequential layer options ----------\n   ----------------------------------------------\n*/\n/**\n * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!)\n * Don't use it if you're not an active lwIP project member\n */\n#ifndef LWIP_TCPIP_CORE_LOCKING\n#define LWIP_TCPIP_CORE_LOCKING         0\n#endif\n\n/**\n * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!)\n * Don't use it if you're not an active lwIP project member\n */\n#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT\n#define LWIP_TCPIP_CORE_LOCKING_INPUT   0\n#endif\n\n/**\n * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)\n */\n#ifndef LWIP_NETCONN\n#define LWIP_NETCONN                    0\n#endif\n\n/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create\n * timers running in tcpip_thread from another thread.\n */\n#ifndef LWIP_TCPIP_TIMEOUT\n#define LWIP_TCPIP_TIMEOUT              1\n#endif\n\n/*\n   ------------------------------------\n   ---------- Socket options ----------\n   ------------------------------------\n*/\n/**\n * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)\n */\n#ifndef LWIP_SOCKET\n#define LWIP_SOCKET                     0\n#endif\n\n/**\n * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names.\n * (only used if you use sockets.c)\n */\n#ifndef LWIP_COMPAT_SOCKETS\n#define LWIP_COMPAT_SOCKETS             1\n#endif\n\n/**\n * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.\n * Disable this option if you use a POSIX operating system that uses the same\n * names (read, write & close). (only used if you use sockets.c)\n */\n#ifndef LWIP_POSIX_SOCKETS_IO_NAMES\n#define LWIP_POSIX_SOCKETS_IO_NAMES     1\n#endif\n\n/**\n * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT\n * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set\n * in seconds. (does not require sockets.c, and will affect tcp.c)\n */\n#ifndef LWIP_TCP_KEEPALIVE\n#define LWIP_TCP_KEEPALIVE              0\n#endif\n\n/**\n * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing.\n */\n#ifndef LWIP_SO_RCVTIMEO\n#define LWIP_SO_RCVTIMEO                0\n#endif\n\n/**\n * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.\n */\n#ifndef LWIP_SO_RCVBUF\n#define LWIP_SO_RCVBUF                  0\n#endif\n\n/**\n * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.\n */\n#ifndef RECV_BUFSIZE_DEFAULT\n#define RECV_BUFSIZE_DEFAULT            INT_MAX\n#endif\n\n/**\n * SO_REUSE==1: Enable SO_REUSEADDR option.\n */\n#ifndef SO_REUSE\n#define SO_REUSE                        0\n#endif\n\n/**\n * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets\n * to all local matches if SO_REUSEADDR is turned on.\n * WARNING: Adds a memcpy for every packet if passing to more than one pcb!\n */\n#ifndef SO_REUSE_RXTOALL\n#define SO_REUSE_RXTOALL                0\n#endif\n\n/*\n   ----------------------------------------\n   ---------- Statistics options ----------\n   ----------------------------------------\n*/\n/**\n * LWIP_STATS==1: Enable statistics collection in lwip_stats.\n */\n#ifndef LWIP_STATS\n#define LWIP_STATS                      1\n#endif\n\n#if LWIP_STATS\n\n/**\n * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions.\n */\n#ifndef LWIP_STATS_DISPLAY\n#define LWIP_STATS_DISPLAY              0\n#endif\n\n/**\n * LINK_STATS==1: Enable link stats.\n */\n#ifndef LINK_STATS\n#define LINK_STATS                      1\n#endif\n\n/**\n * ETHARP_STATS==1: Enable etharp stats.\n */\n#ifndef ETHARP_STATS\n#define ETHARP_STATS                    (LWIP_ARP)\n#endif\n\n/**\n * IP_STATS==1: Enable IP stats.\n */\n#ifndef IP_STATS\n#define IP_STATS                        1\n#endif\n\n/**\n * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is\n * on if using either frag or reass.\n */\n#ifndef IPFRAG_STATS\n#define IPFRAG_STATS                    (IP_REASSEMBLY || IP_FRAG)\n#endif\n\n/**\n * ICMP_STATS==1: Enable ICMP stats.\n */\n#ifndef ICMP_STATS\n#define ICMP_STATS                      1\n#endif\n\n/**\n * IGMP_STATS==1: Enable IGMP stats.\n */\n#ifndef IGMP_STATS\n#define IGMP_STATS                      (LWIP_IGMP)\n#endif\n\n/**\n * UDP_STATS==1: Enable UDP stats. Default is on if\n * UDP enabled, otherwise off.\n */\n#ifndef UDP_STATS\n#define UDP_STATS                       (LWIP_UDP)\n#endif\n\n/**\n * TCP_STATS==1: Enable TCP stats. Default is on if TCP\n * enabled, otherwise off.\n */\n#ifndef TCP_STATS\n#define TCP_STATS                       (LWIP_TCP)\n#endif\n\n/**\n * MEM_STATS==1: Enable mem.c stats.\n */\n#ifndef MEM_STATS\n#define MEM_STATS                       ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0))\n#endif\n\n/**\n * MEMP_STATS==1: Enable memp.c pool stats.\n */\n#ifndef MEMP_STATS\n#define MEMP_STATS                      (MEMP_MEM_MALLOC == 0)\n#endif\n\n/**\n * SYS_STATS==1: Enable system stats (sem and mbox counts, etc).\n */\n#ifndef SYS_STATS\n#define SYS_STATS                       (NO_SYS == 0)\n#endif\n\n#else\n\n#define LINK_STATS                      0\n#define IP_STATS                        0\n#define IPFRAG_STATS                    0\n#define ICMP_STATS                      0\n#define IGMP_STATS                      0\n#define UDP_STATS                       0\n#define TCP_STATS                       0\n#define MEM_STATS                       0\n#define MEMP_STATS                      0\n#define SYS_STATS                       0\n#define LWIP_STATS_DISPLAY              0\n\n#endif /* LWIP_STATS */\n\n/*\n   ---------------------------------\n   ---------- PPP options ----------\n   ---------------------------------\n*/\n/**\n * PPP_SUPPORT==1: Enable PPP.\n */\n#ifndef PPP_SUPPORT\n#define PPP_SUPPORT                     0\n#endif\n\n/**\n * PPPOE_SUPPORT==1: Enable PPP Over Ethernet\n */\n#ifndef PPPOE_SUPPORT\n#define PPPOE_SUPPORT                   0\n#endif\n\n/**\n * PPPOS_SUPPORT==1: Enable PPP Over Serial\n */\n#ifndef PPPOS_SUPPORT\n#define PPPOS_SUPPORT                   PPP_SUPPORT\n#endif\n\n#if PPP_SUPPORT\n\n/**\n * NUM_PPP: Max PPP sessions.\n */\n#ifndef NUM_PPP\n#define NUM_PPP                         1\n#endif\n\n/**\n * PAP_SUPPORT==1: Support PAP.\n */\n#ifndef PAP_SUPPORT\n#define PAP_SUPPORT                     0\n#endif\n\n/**\n * CHAP_SUPPORT==1: Support CHAP.\n */\n#ifndef CHAP_SUPPORT\n#define CHAP_SUPPORT                    0\n#endif\n\n/**\n * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET!\n */\n#ifndef MSCHAP_SUPPORT\n#define MSCHAP_SUPPORT                  0\n#endif\n\n/**\n * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET!\n */\n#ifndef CBCP_SUPPORT\n#define CBCP_SUPPORT                    0\n#endif\n\n/**\n * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET!\n */\n#ifndef CCP_SUPPORT\n#define CCP_SUPPORT                     0\n#endif\n\n/**\n * VJ_SUPPORT==1: Support VJ header compression.\n */\n#ifndef VJ_SUPPORT\n#define VJ_SUPPORT                      0\n#endif\n\n/**\n * MD5_SUPPORT==1: Support MD5 (see also CHAP).\n */\n#ifndef MD5_SUPPORT\n#define MD5_SUPPORT                     0\n#endif\n\n/*\n * Timeouts\n */\n#ifndef FSM_DEFTIMEOUT\n#define FSM_DEFTIMEOUT                  6       /* Timeout time in seconds */\n#endif\n\n#ifndef FSM_DEFMAXTERMREQS\n#define FSM_DEFMAXTERMREQS              2       /* Maximum Terminate-Request transmissions */\n#endif\n\n#ifndef FSM_DEFMAXCONFREQS\n#define FSM_DEFMAXCONFREQS              10      /* Maximum Configure-Request transmissions */\n#endif\n\n#ifndef FSM_DEFMAXNAKLOOPS\n#define FSM_DEFMAXNAKLOOPS              5       /* Maximum number of nak loops */\n#endif\n\n#ifndef UPAP_DEFTIMEOUT\n#define UPAP_DEFTIMEOUT                 6       /* Timeout (seconds) for retransmitting req */\n#endif\n\n#ifndef UPAP_DEFREQTIME\n#define UPAP_DEFREQTIME                 30      /* Time to wait for auth-req from peer */\n#endif\n\n#ifndef CHAP_DEFTIMEOUT\n#define CHAP_DEFTIMEOUT                 6       /* Timeout time in seconds */\n#endif\n\n#ifndef CHAP_DEFTRANSMITS\n#define CHAP_DEFTRANSMITS               10      /* max # times to send challenge */\n#endif\n\n/* Interval in seconds between keepalive echo requests, 0 to disable. */\n#ifndef LCP_ECHOINTERVAL\n#define LCP_ECHOINTERVAL                0\n#endif\n\n/* Number of unanswered echo requests before failure. */\n#ifndef LCP_MAXECHOFAILS\n#define LCP_MAXECHOFAILS                3\n#endif\n\n/* Max Xmit idle time (in jiffies) before resend flag char. */\n#ifndef PPP_MAXIDLEFLAG\n#define PPP_MAXIDLEFLAG                 100\n#endif\n\n/*\n * Packet sizes\n *\n * Note - lcp shouldn't be allowed to negotiate stuff outside these\n *    limits.  See lcp.h in the pppd directory.\n * (XXX - these constants should simply be shared by lcp.c instead\n *    of living in lcp.h)\n */\n#define PPP_MTU                         1500     /* Default MTU (size of Info field) */\n#ifndef PPP_MAXMTU\n/* #define PPP_MAXMTU  65535 - (PPP_HDRLEN + PPP_FCSLEN) */\n#define PPP_MAXMTU                      1500 /* Largest MTU we allow */\n#endif\n#define PPP_MINMTU                      64\n#define PPP_MRU                         1500     /* default MRU = max length of info field */\n#define PPP_MAXMRU                      1500     /* Largest MRU we allow */\n#ifndef PPP_DEFMRU\n#define PPP_DEFMRU                      296             /* Try for this */\n#endif\n#define PPP_MINMRU                      128             /* No MRUs below this */\n\n#ifndef MAXNAMELEN\n#define MAXNAMELEN                      256     /* max length of hostname or name for auth */\n#endif\n#ifndef MAXSECRETLEN\n#define MAXSECRETLEN                    256     /* max length of password or secret */\n#endif\n\n#endif /* PPP_SUPPORT */\n\n/*\n   --------------------------------------\n   ---------- Checksum options ----------\n   --------------------------------------\n*/\n/**\n * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.\n */\n#ifndef CHECKSUM_GEN_IP\n#define CHECKSUM_GEN_IP                 1\n#endif\n \n/**\n * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.\n */\n#ifndef CHECKSUM_GEN_UDP\n#define CHECKSUM_GEN_UDP                1\n#endif\n \n/**\n * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.\n */\n#ifndef CHECKSUM_GEN_TCP\n#define CHECKSUM_GEN_TCP                1\n#endif\n \n/**\n * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.\n */\n#ifndef CHECKSUM_CHECK_IP\n#define CHECKSUM_CHECK_IP               1\n#endif\n \n/**\n * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.\n */\n#ifndef CHECKSUM_CHECK_UDP\n#define CHECKSUM_CHECK_UDP              1\n#endif\n\n/**\n * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.\n */\n#ifndef CHECKSUM_CHECK_TCP\n#define CHECKSUM_CHECK_TCP              1\n#endif\n\n/**\n * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from\n * application buffers to pbufs.\n */\n#ifndef LWIP_CHECKSUM_ON_COPY\n#define LWIP_CHECKSUM_ON_COPY           0\n#endif\n\n/*\n   ---------------------------------------\n   ---------- Debugging options ----------\n   ---------------------------------------\n*/\n/**\n * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is\n * compared against this value. If it is smaller, then debugging\n * messages are written.\n */\n#ifndef LWIP_DBG_MIN_LEVEL\n#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL\n#endif\n\n/**\n * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable\n * debug messages of certain types.\n */\n#ifndef LWIP_DBG_TYPES_ON\n#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON\n#endif\n\n/**\n * ETHARP_DEBUG: Enable debugging in etharp.c.\n */\n#ifndef ETHARP_DEBUG\n#define ETHARP_DEBUG                    LWIP_DBG_OFF\n#endif\n\n/**\n * NETIF_DEBUG: Enable debugging in netif.c.\n */\n#ifndef NETIF_DEBUG\n#define NETIF_DEBUG                     LWIP_DBG_OFF\n#endif\n\n/**\n * PBUF_DEBUG: Enable debugging in pbuf.c.\n */\n#ifndef PBUF_DEBUG\n#define PBUF_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * API_LIB_DEBUG: Enable debugging in api_lib.c.\n */\n#ifndef API_LIB_DEBUG\n#define API_LIB_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * API_MSG_DEBUG: Enable debugging in api_msg.c.\n */\n#ifndef API_MSG_DEBUG\n#define API_MSG_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * SOCKETS_DEBUG: Enable debugging in sockets.c.\n */\n#ifndef SOCKETS_DEBUG\n#define SOCKETS_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * ICMP_DEBUG: Enable debugging in icmp.c.\n */\n#ifndef ICMP_DEBUG\n#define ICMP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * IGMP_DEBUG: Enable debugging in igmp.c.\n */\n#ifndef IGMP_DEBUG\n#define IGMP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * INET_DEBUG: Enable debugging in inet.c.\n */\n#ifndef INET_DEBUG\n#define INET_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * IP_DEBUG: Enable debugging for IP.\n */\n#ifndef IP_DEBUG\n#define IP_DEBUG                        LWIP_DBG_OFF\n#endif\n\n/**\n * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass.\n */\n#ifndef IP_REASS_DEBUG\n#define IP_REASS_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * RAW_DEBUG: Enable debugging in raw.c.\n */\n#ifndef RAW_DEBUG\n#define RAW_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * MEM_DEBUG: Enable debugging in mem.c.\n */\n#ifndef MEM_DEBUG\n#define MEM_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * MEMP_DEBUG: Enable debugging in memp.c.\n */\n#ifndef MEMP_DEBUG\n#define MEMP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * SYS_DEBUG: Enable debugging in sys.c.\n */\n#ifndef SYS_DEBUG\n#define SYS_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * TIMERS_DEBUG: Enable debugging in timers.c.\n */\n#ifndef TIMERS_DEBUG\n#define TIMERS_DEBUG                    LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_DEBUG: Enable debugging for TCP.\n */\n#ifndef TCP_DEBUG\n#define TCP_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.\n */\n#ifndef TCP_INPUT_DEBUG\n#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit.\n */\n#ifndef TCP_FR_DEBUG\n#define TCP_FR_DEBUG                    LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit\n * timeout.\n */\n#ifndef TCP_RTO_DEBUG\n#define TCP_RTO_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_CWND_DEBUG: Enable debugging for TCP congestion window.\n */\n#ifndef TCP_CWND_DEBUG\n#define TCP_CWND_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating.\n */\n#ifndef TCP_WND_DEBUG\n#define TCP_WND_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.\n */\n#ifndef TCP_OUTPUT_DEBUG\n#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_RST_DEBUG: Enable debugging for TCP with the RST message.\n */\n#ifndef TCP_RST_DEBUG\n#define TCP_RST_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths.\n */\n#ifndef TCP_QLEN_DEBUG\n#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * UDP_DEBUG: Enable debugging in UDP.\n */\n#ifndef UDP_DEBUG\n#define UDP_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * TCPIP_DEBUG: Enable debugging in tcpip.c.\n */\n#ifndef TCPIP_DEBUG\n#define TCPIP_DEBUG                     LWIP_DBG_OFF\n#endif\n\n/**\n * PPP_DEBUG: Enable debugging for PPP.\n */\n#ifndef PPP_DEBUG\n#define PPP_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * SLIP_DEBUG: Enable debugging in slipif.c.\n */\n#ifndef SLIP_DEBUG\n#define SLIP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * DHCP_DEBUG: Enable debugging in dhcp.c.\n */\n#ifndef DHCP_DEBUG\n#define DHCP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * AUTOIP_DEBUG: Enable debugging in autoip.c.\n */\n#ifndef AUTOIP_DEBUG\n#define AUTOIP_DEBUG                    LWIP_DBG_OFF\n#endif\n\n/**\n * SNMP_MSG_DEBUG: Enable debugging for SNMP messages.\n */\n#ifndef SNMP_MSG_DEBUG\n#define SNMP_MSG_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs.\n */\n#ifndef SNMP_MIB_DEBUG\n#define SNMP_MIB_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * DNS_DEBUG: Enable debugging for DNS.\n */\n#ifndef DNS_DEBUG\n#define DNS_DEBUG                       LWIP_DBG_OFF\n#endif\n\n#endif /* __LWIP_OPT_H__ */\n"
  },
  {
    "path": "app/include/lwip/pbuf.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#ifndef __LWIP_PBUF_H__\n#define __LWIP_PBUF_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** Currently, the pbuf_custom code is only needed for one specific configuration\n * of IP_FRAG */\n#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)\n\n#define PBUF_TRANSPORT_HLEN 20\n#define PBUF_IP_HLEN        20\n\ntypedef enum {\n  PBUF_TRANSPORT,\n  PBUF_IP,\n  PBUF_LINK,\n  PBUF_RAW\n} pbuf_layer;\n\ntypedef enum {\n  PBUF_RAM, /* pbuf data is stored in RAM */\n  PBUF_ROM, /* pbuf data is stored in ROM */\n  PBUF_REF, /* pbuf comes from the pbuf pool */\n  PBUF_POOL, /* pbuf payload refers to RAM */\n#ifdef EBUF_LWIP\n  PBUF_ESF_RX /* pbuf payload is from WLAN */\n#endif /* ESF_LWIP */\n} pbuf_type;\n\n\n/** indicates this packet's data should be immediately passed to the application */\n#define PBUF_FLAG_PUSH      0x01U\n/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a\n    a pbuf differently */\n#define PBUF_FLAG_IS_CUSTOM 0x02U\n/** indicates this pbuf is UDP multicast to be looped back */\n#define PBUF_FLAG_MCASTLOOP 0x04U\n\nstruct pbuf {\n  /** next pbuf in singly linked pbuf chain */\n  struct pbuf *next;\n\n  /** pointer to the actual data in the buffer */\n  void *payload;\n\n  /**\n   * total length of this buffer and all next buffers in chain\n   * belonging to the same packet.\n   *\n   * For non-queue packet chains this is the invariant:\n   * p->tot_len == p->len + (p->next? p->next->tot_len: 0)\n   */\n  u16_t tot_len;\n\n  /** length of this buffer */\n  u16_t len;\n\n  /** pbuf_type as u8_t instead of enum to save space */\n  u8_t /*pbuf_type*/ type;\n\n  /** misc flags */\n  u8_t flags;\n\n  /**\n   * the reference count always equals the number of pointers\n   * that refer to this pbuf. This can be pointers from an application,\n   * the stack itself, or pbuf->next pointers from a chain.\n   */\n  u16_t ref;\n  \n  /* add a pointer for esf_buf */\n  void * eb; \n};\n\n#if LWIP_SUPPORT_CUSTOM_PBUF\n/** Prototype for a function to free a custom pbuf */\ntypedef void (*pbuf_free_custom_fn)(struct pbuf *p);\n  \n/** A custom pbuf: like a pbuf, but following a function pointer to free it. */\nstruct pbuf_custom {\n  /** The actual pbuf */\n  struct pbuf pbuf;\n  /** This function is called when pbuf_free deallocates this pbuf(_custom) */\n  pbuf_free_custom_fn custom_free_function;\n};\n#endif /* LWIP_SUPPORT_CUSTOM_PBUF */\n\n/* Initializes the pbuf module. This call is empty for now, but may not be in future. */\n#define pbuf_init()\n\nstruct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)ICACHE_FLASH_ATTR;\n#if LWIP_SUPPORT_CUSTOM_PBUF\nstruct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type,\n                                 struct pbuf_custom *p, void *payload_mem,\n                                 u16_t payload_mem_len)ICACHE_FLASH_ATTR;\n#endif /* LWIP_SUPPORT_CUSTOM_PBUF */\nvoid pbuf_realloc(struct pbuf *p, u16_t size)ICACHE_FLASH_ATTR;\nu8_t pbuf_header(struct pbuf *p, s16_t header_size)ICACHE_FLASH_ATTR;\nvoid pbuf_ref(struct pbuf *p)ICACHE_FLASH_ATTR;\nu8_t pbuf_free(struct pbuf *p)ICACHE_FLASH_ATTR;\nu8_t pbuf_clen(struct pbuf *p)ICACHE_FLASH_ATTR;\nvoid pbuf_cat(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR;\nvoid pbuf_chain(struct pbuf *head, struct pbuf *tail)ICACHE_FLASH_ATTR;\nstruct pbuf *pbuf_dechain(struct pbuf *p)ICACHE_FLASH_ATTR;\nerr_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)ICACHE_FLASH_ATTR;\nu16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset)ICACHE_FLASH_ATTR;\nerr_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)ICACHE_FLASH_ATTR;\nstruct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer)ICACHE_FLASH_ATTR;\n#if LWIP_CHECKSUM_ON_COPY\nerr_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,\n                       u16_t len, u16_t *chksum)ICACHE_FLASH_ATTR;\n#endif /* LWIP_CHECKSUM_ON_COPY */\n\nu8_t pbuf_get_at(struct pbuf* p, u16_t offset)ICACHE_FLASH_ATTR;\nu16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)ICACHE_FLASH_ATTR;\nu16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)ICACHE_FLASH_ATTR;\nu16_t pbuf_strstr(struct pbuf* p, const char* substr)ICACHE_FLASH_ATTR;\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_PBUF_H__ */\n"
  },
  {
    "path": "app/include/lwip/puck_def.h",
    "content": "/*\r\n * puck_def.h\r\n *\r\n *  Created on: Jul 22, 2010\r\n *      Author: dtoma\r\n */\r\n\r\n#ifndef PUCK_DEF_H_\r\n#define PUCK_DEF_H_\r\n\r\n\r\n\r\n#define INSTRUMENT_PORT      8760\r\n\r\n#define INSTRUMENT_LENGTH    80\r\n\r\n#define MDNS_NAME_LENGTH     68 //68\r\n\r\nchar* PUCK_SERVICE    = NULL;\r\n//#define PUCK_SERVICE\t\"_Escpressif._tcp.local\"\r\n#define DNS_SD_SERVICE       \"_services._dns-sd._udp.local\"\r\n#define SERVICE_DESCRIPTION  \"PUCK PROTOCOL\"\r\n#define PUCK_SERVICE_LENGTH  30\r\n\r\n#define UUID_LEN      \t\t \t16\r\n#define DS_VERS_LEN    \t\t\t2\r\n#define DS_SIZE_LEN    \t\t\t2\r\n#define MAN_ID_LEN     \t\t\t4\r\n#define MAN_MODEL_LEN  \t\t\t2\r\n#define MAN_VERS_LEN   \t\t\t2\r\n#define SER_NUM_LEN    \t\t\t4\r\n#define NAME_LEN       \t\t\t64\r\n#define PUCK_DATASHEET_SIZE   \t96\r\n\r\n#define UUID_OFFSET       0\r\n#define DS_VERS_OFFSET    UUID_LEN + UUID_OFFSET\r\n#define DS_SIZE_OFFSET    DS_VERS_LEN + DS_VERS_OFFSET\r\n#define MAN_ID_OFFSET     DS_SIZE_LEN + DS_SIZE_OFFSET\r\n#define MAN_MODEL_OFFSET  MAN_ID_LEN + MAN_ID_OFFSET\r\n#define MAN_VERS_OFFSET   MAN_MODEL_LEN + MAN_MODEL_OFFSET\r\n#define SER_NUM_OFFSET    MAN_VERS_LEN + MAN_VERS_OFFSET\r\n#define NAME_OFFSET       SER_NUM_LEN + SER_NUM_OFFSET\r\n\r\n#endif /* __PUCK_DEF_H__ */\r\n"
  },
  {
    "path": "app/include/lwip/raw.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_RAW_H__\n#define __LWIP_RAW_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/pbuf.h\"\n#include \"lwip/def.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/ip_addr.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct raw_pcb;\n\n/** Function prototype for raw pcb receive callback functions.\n * @param arg user supplied argument (raw_pcb.recv_arg)\n * @param pcb the raw_pcb which received data\n * @param p the packet buffer that was received\n * @param addr the remote IP address from which the packet was received\n * @return 1 if the packet was 'eaten' (aka. deleted),\n *         0 if the packet lives on\n * If returning 1, the callback is responsible for freeing the pbuf\n * if it's not used any more.\n */\ntypedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,\n    ip_addr_t *addr);\n\nstruct raw_pcb {\n  /* Common members of all PCB types */\n  IP_PCB;\n\n  struct raw_pcb *next;\n\n  u8_t protocol;\n\n  /** receive callback function */\n  raw_recv_fn recv;\n  /* user-supplied argument for the recv callback */\n  void *recv_arg;\n};\n\n/* The following functions is the application layer interface to the\n   RAW code. */\nstruct raw_pcb * raw_new        (u8_t proto)ICACHE_FLASH_ATTR;\nvoid             raw_remove     (struct raw_pcb *pcb)ICACHE_FLASH_ATTR;\nerr_t            raw_bind       (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;\nerr_t            raw_connect    (struct raw_pcb *pcb, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;\n\nvoid             raw_recv       (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)ICACHE_FLASH_ATTR;\nerr_t            raw_sendto     (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;\nerr_t            raw_send       (struct raw_pcb *pcb, struct pbuf *p);\n\n/* The following functions are the lower layer interface to RAW. */\nu8_t             raw_input      (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR;\n#define raw_init() /* Compatibility define, not init needed. */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_RAW */\n\n#endif /* __LWIP_RAW_H__ */\n"
  },
  {
    "path": "app/include/lwip/sio.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n */\n\n/*\n * This is the interface to the platform specific serial IO module\n * It needs to be implemented by those platforms which need SLIP or PPP\n */\n\n#ifndef __SIO_H__\n#define __SIO_H__\n\n#include \"lwip/arch.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* If you want to define sio_fd_t elsewhere or differently,\n   define this in your cc.h file. */\n#ifndef __sio_fd_t_defined\ntypedef void * sio_fd_t;\n#endif\n\n/* The following functions can be defined to something else in your cc.h file\n   or be implemented in your custom sio.c file. */\n\n#ifndef sio_open\n/**\n * Opens a serial device for communication.\n * \n * @param devnum device number\n * @return handle to serial device if successful, NULL otherwise\n */\nsio_fd_t sio_open(u8_t devnum)ICACHE_FLASH_ATTR;\n#endif\n\n#ifndef sio_send\n/**\n * Sends a single character to the serial device.\n * \n * @param c character to send\n * @param fd serial device handle\n * \n * @note This function will block until the character can be sent.\n */\nvoid sio_send(u8_t c, sio_fd_t fd)ICACHE_FLASH_ATTR;\n#endif\n\n#ifndef sio_recv\n/**\n * Receives a single character from the serial device.\n * \n * @param fd serial device handle\n * \n * @note This function will block until a character is received.\n */\nu8_t sio_recv(sio_fd_t fd)ICACHE_FLASH_ATTR;\n#endif\n\n#ifndef sio_read\n/**\n * Reads from the serial device.\n * \n * @param fd serial device handle\n * @param data pointer to data buffer for receiving\n * @param len maximum length (in bytes) of data to receive\n * @return number of bytes actually received - may be 0 if aborted by sio_read_abort\n * \n * @note This function will block until data can be received. The blocking\n * can be cancelled by calling sio_read_abort().\n */\nu32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR;\n#endif\n\n#ifndef sio_tryread\n/**\n * Tries to read from the serial device. Same as sio_read but returns\n * immediately if no data is available and never blocks.\n * \n * @param fd serial device handle\n * @param data pointer to data buffer for receiving\n * @param len maximum length (in bytes) of data to receive\n * @return number of bytes actually received\n */\nu32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR;\n#endif\n\n#ifndef sio_write\n/**\n * Writes to the serial device.\n * \n * @param fd serial device handle\n * @param data pointer to data to send\n * @param len length (in bytes) of data to send\n * @return number of bytes actually sent\n * \n * @note This function will block until all data can be sent.\n */\nu32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len)ICACHE_FLASH_ATTR;\n#endif\n\n#ifndef sio_read_abort\n/**\n * Aborts a blocking sio_read() call.\n * \n * @param fd serial device handle\n */\nvoid sio_read_abort(sio_fd_t fd)ICACHE_FLASH_ATTR;\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __SIO_H__ */\n"
  },
  {
    "path": "app/include/lwip/snmp.h",
    "content": "/*\n * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>\n * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands.\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Leon Woestenberg <leon.woestenberg@axon.tv>\n *\n */\n#ifndef __LWIP_SNMP_H__\n#define __LWIP_SNMP_H__\n\n#include \"lwip/opt.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"lwip/ip_addr.h\"\n\nstruct udp_pcb;\nstruct netif;\n\n/**\n * @see RFC1213, \"MIB-II, 6. Definitions\"\n */\nenum snmp_ifType {\n  snmp_ifType_other=1,                /* none of the following */\n  snmp_ifType_regular1822,\n  snmp_ifType_hdh1822,\n  snmp_ifType_ddn_x25,\n  snmp_ifType_rfc877_x25,\n  snmp_ifType_ethernet_csmacd,\n  snmp_ifType_iso88023_csmacd,\n  snmp_ifType_iso88024_tokenBus,\n  snmp_ifType_iso88025_tokenRing,\n  snmp_ifType_iso88026_man,\n  snmp_ifType_starLan,\n  snmp_ifType_proteon_10Mbit,\n  snmp_ifType_proteon_80Mbit,\n  snmp_ifType_hyperchannel,\n  snmp_ifType_fddi,\n  snmp_ifType_lapb,\n  snmp_ifType_sdlc,\n  snmp_ifType_ds1,                    /* T-1 */\n  snmp_ifType_e1,                     /* european equiv. of T-1 */\n  snmp_ifType_basicISDN,\n  snmp_ifType_primaryISDN,            /* proprietary serial */\n  snmp_ifType_propPointToPointSerial,\n  snmp_ifType_ppp,\n  snmp_ifType_softwareLoopback,\n  snmp_ifType_eon,                    /* CLNP over IP [11] */\n  snmp_ifType_ethernet_3Mbit,\n  snmp_ifType_nsip,                   /* XNS over IP */\n  snmp_ifType_slip,                   /* generic SLIP */\n  snmp_ifType_ultra,                  /* ULTRA technologies */\n  snmp_ifType_ds3,                    /* T-3 */\n  snmp_ifType_sip,                    /* SMDS */\n  snmp_ifType_frame_relay\n};\n\n#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\n\n/** SNMP \"sysuptime\" Interval */\n#define SNMP_SYSUPTIME_INTERVAL 10\n\n/** fixed maximum length for object identifier type */\n#define LWIP_SNMP_OBJ_ID_LEN 32\n\n/** internal object identifier representation */\nstruct snmp_obj_id\n{\n  u8_t len;\n  s32_t id[LWIP_SNMP_OBJ_ID_LEN];\n};\n\n/* system */\nvoid snmp_set_sysdesr(u8_t* str, u8_t* len);\nvoid snmp_set_sysobjid(struct snmp_obj_id *oid);\nvoid snmp_get_sysobjid_ptr(struct snmp_obj_id **oid);\nvoid snmp_inc_sysuptime(void);\nvoid snmp_add_sysuptime(u32_t value);\nvoid snmp_get_sysuptime(u32_t *value);\nvoid snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen);\nvoid snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen);\nvoid snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen);\n\n/* network interface */\nvoid snmp_add_ifinoctets(struct netif *ni, u32_t value); \nvoid snmp_inc_ifinucastpkts(struct netif *ni);\nvoid snmp_inc_ifinnucastpkts(struct netif *ni);\nvoid snmp_inc_ifindiscards(struct netif *ni);\nvoid snmp_add_ifoutoctets(struct netif *ni, u32_t value);\nvoid snmp_inc_ifoutucastpkts(struct netif *ni);\nvoid snmp_inc_ifoutnucastpkts(struct netif *ni);\nvoid snmp_inc_ifoutdiscards(struct netif *ni);\nvoid snmp_inc_iflist(void);\nvoid snmp_dec_iflist(void);\n\n/* ARP (for atTable and ipNetToMediaTable) */\nvoid snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip);\nvoid snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip);\n\n/* IP */\nvoid snmp_inc_ipinreceives(void);\nvoid snmp_inc_ipinhdrerrors(void);\nvoid snmp_inc_ipinaddrerrors(void);\nvoid snmp_inc_ipforwdatagrams(void);\nvoid snmp_inc_ipinunknownprotos(void);\nvoid snmp_inc_ipindiscards(void);\nvoid snmp_inc_ipindelivers(void);\nvoid snmp_inc_ipoutrequests(void);\nvoid snmp_inc_ipoutdiscards(void);\nvoid snmp_inc_ipoutnoroutes(void);\nvoid snmp_inc_ipreasmreqds(void);\nvoid snmp_inc_ipreasmoks(void);\nvoid snmp_inc_ipreasmfails(void);\nvoid snmp_inc_ipfragoks(void);\nvoid snmp_inc_ipfragfails(void);\nvoid snmp_inc_ipfragcreates(void);\nvoid snmp_inc_iproutingdiscards(void);\nvoid snmp_insert_ipaddridx_tree(struct netif *ni);\nvoid snmp_delete_ipaddridx_tree(struct netif *ni);\nvoid snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni);\nvoid snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni);\n\n/* ICMP */\nvoid snmp_inc_icmpinmsgs(void);\nvoid snmp_inc_icmpinerrors(void);\nvoid snmp_inc_icmpindestunreachs(void);\nvoid snmp_inc_icmpintimeexcds(void);\nvoid snmp_inc_icmpinparmprobs(void);\nvoid snmp_inc_icmpinsrcquenchs(void);\nvoid snmp_inc_icmpinredirects(void);\nvoid snmp_inc_icmpinechos(void);\nvoid snmp_inc_icmpinechoreps(void);\nvoid snmp_inc_icmpintimestamps(void);\nvoid snmp_inc_icmpintimestampreps(void);\nvoid snmp_inc_icmpinaddrmasks(void);\nvoid snmp_inc_icmpinaddrmaskreps(void);\nvoid snmp_inc_icmpoutmsgs(void);\nvoid snmp_inc_icmpouterrors(void);\nvoid snmp_inc_icmpoutdestunreachs(void);\nvoid snmp_inc_icmpouttimeexcds(void);\nvoid snmp_inc_icmpoutparmprobs(void);\nvoid snmp_inc_icmpoutsrcquenchs(void);\nvoid snmp_inc_icmpoutredirects(void); \nvoid snmp_inc_icmpoutechos(void);\nvoid snmp_inc_icmpoutechoreps(void);\nvoid snmp_inc_icmpouttimestamps(void);\nvoid snmp_inc_icmpouttimestampreps(void);\nvoid snmp_inc_icmpoutaddrmasks(void);\nvoid snmp_inc_icmpoutaddrmaskreps(void);\n\n/* TCP */\nvoid snmp_inc_tcpactiveopens(void);\nvoid snmp_inc_tcppassiveopens(void);\nvoid snmp_inc_tcpattemptfails(void);\nvoid snmp_inc_tcpestabresets(void);\nvoid snmp_inc_tcpinsegs(void);\nvoid snmp_inc_tcpoutsegs(void);\nvoid snmp_inc_tcpretranssegs(void);\nvoid snmp_inc_tcpinerrs(void);\nvoid snmp_inc_tcpoutrsts(void);\n\n/* UDP */\nvoid snmp_inc_udpindatagrams(void);\nvoid snmp_inc_udpnoports(void);\nvoid snmp_inc_udpinerrors(void);\nvoid snmp_inc_udpoutdatagrams(void);\nvoid snmp_insert_udpidx_tree(struct udp_pcb *pcb);\nvoid snmp_delete_udpidx_tree(struct udp_pcb *pcb);\n\n/* SNMP */\nvoid snmp_inc_snmpinpkts(void);\nvoid snmp_inc_snmpoutpkts(void);\nvoid snmp_inc_snmpinbadversions(void);\nvoid snmp_inc_snmpinbadcommunitynames(void);\nvoid snmp_inc_snmpinbadcommunityuses(void);\nvoid snmp_inc_snmpinasnparseerrs(void);\nvoid snmp_inc_snmpintoobigs(void);\nvoid snmp_inc_snmpinnosuchnames(void);\nvoid snmp_inc_snmpinbadvalues(void);\nvoid snmp_inc_snmpinreadonlys(void);\nvoid snmp_inc_snmpingenerrs(void);\nvoid snmp_add_snmpintotalreqvars(u8_t value);\nvoid snmp_add_snmpintotalsetvars(u8_t value);\nvoid snmp_inc_snmpingetrequests(void);\nvoid snmp_inc_snmpingetnexts(void);\nvoid snmp_inc_snmpinsetrequests(void);\nvoid snmp_inc_snmpingetresponses(void);\nvoid snmp_inc_snmpintraps(void);\nvoid snmp_inc_snmpouttoobigs(void);\nvoid snmp_inc_snmpoutnosuchnames(void);\nvoid snmp_inc_snmpoutbadvalues(void);\nvoid snmp_inc_snmpoutgenerrs(void);\nvoid snmp_inc_snmpoutgetrequests(void);\nvoid snmp_inc_snmpoutgetnexts(void);\nvoid snmp_inc_snmpoutsetrequests(void);\nvoid snmp_inc_snmpoutgetresponses(void);\nvoid snmp_inc_snmpouttraps(void);\nvoid snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid);\nvoid snmp_set_snmpenableauthentraps(u8_t *value);\nvoid snmp_get_snmpenableauthentraps(u8_t *value);\n\n/* LWIP_SNMP support not available */\n/* define everything to be empty */\n#else\n\n/* system */\n#define snmp_set_sysdesr(str, len)\n#define snmp_set_sysobjid(oid);\n#define snmp_get_sysobjid_ptr(oid)\n#define snmp_inc_sysuptime()\n#define snmp_add_sysuptime(value)\n#define snmp_get_sysuptime(value)\n#define snmp_set_syscontact(ocstr, ocstrlen);\n#define snmp_set_sysname(ocstr, ocstrlen);\n#define snmp_set_syslocation(ocstr, ocstrlen);\n\n/* network interface */\n#define snmp_add_ifinoctets(ni,value) \n#define snmp_inc_ifinucastpkts(ni)\n#define snmp_inc_ifinnucastpkts(ni)\n#define snmp_inc_ifindiscards(ni)\n#define snmp_add_ifoutoctets(ni,value)\n#define snmp_inc_ifoutucastpkts(ni)\n#define snmp_inc_ifoutnucastpkts(ni)\n#define snmp_inc_ifoutdiscards(ni)\n#define snmp_inc_iflist()\n#define snmp_dec_iflist()\n\n/* ARP */\n#define snmp_insert_arpidx_tree(ni,ip)\n#define snmp_delete_arpidx_tree(ni,ip)\n\n/* IP */\n#define snmp_inc_ipinreceives()\n#define snmp_inc_ipinhdrerrors()\n#define snmp_inc_ipinaddrerrors()\n#define snmp_inc_ipforwdatagrams()\n#define snmp_inc_ipinunknownprotos()\n#define snmp_inc_ipindiscards()\n#define snmp_inc_ipindelivers()\n#define snmp_inc_ipoutrequests()\n#define snmp_inc_ipoutdiscards()\n#define snmp_inc_ipoutnoroutes()\n#define snmp_inc_ipreasmreqds()\n#define snmp_inc_ipreasmoks()\n#define snmp_inc_ipreasmfails()\n#define snmp_inc_ipfragoks()\n#define snmp_inc_ipfragfails()\n#define snmp_inc_ipfragcreates()\n#define snmp_inc_iproutingdiscards()\n#define snmp_insert_ipaddridx_tree(ni)\n#define snmp_delete_ipaddridx_tree(ni)\n#define snmp_insert_iprteidx_tree(dflt, ni)\n#define snmp_delete_iprteidx_tree(dflt, ni)\n\n/* ICMP */\n#define snmp_inc_icmpinmsgs()\n#define snmp_inc_icmpinerrors() \n#define snmp_inc_icmpindestunreachs() \n#define snmp_inc_icmpintimeexcds()\n#define snmp_inc_icmpinparmprobs() \n#define snmp_inc_icmpinsrcquenchs() \n#define snmp_inc_icmpinredirects() \n#define snmp_inc_icmpinechos() \n#define snmp_inc_icmpinechoreps()\n#define snmp_inc_icmpintimestamps() \n#define snmp_inc_icmpintimestampreps()\n#define snmp_inc_icmpinaddrmasks()\n#define snmp_inc_icmpinaddrmaskreps()\n#define snmp_inc_icmpoutmsgs()\n#define snmp_inc_icmpouterrors()\n#define snmp_inc_icmpoutdestunreachs() \n#define snmp_inc_icmpouttimeexcds() \n#define snmp_inc_icmpoutparmprobs()\n#define snmp_inc_icmpoutsrcquenchs()\n#define snmp_inc_icmpoutredirects() \n#define snmp_inc_icmpoutechos() \n#define snmp_inc_icmpoutechoreps()\n#define snmp_inc_icmpouttimestamps()\n#define snmp_inc_icmpouttimestampreps()\n#define snmp_inc_icmpoutaddrmasks()\n#define snmp_inc_icmpoutaddrmaskreps()\n/* TCP */\n#define snmp_inc_tcpactiveopens()\n#define snmp_inc_tcppassiveopens()\n#define snmp_inc_tcpattemptfails()\n#define snmp_inc_tcpestabresets()\n#define snmp_inc_tcpinsegs()\n#define snmp_inc_tcpoutsegs()\n#define snmp_inc_tcpretranssegs()\n#define snmp_inc_tcpinerrs()\n#define snmp_inc_tcpoutrsts()\n\n/* UDP */\n#define snmp_inc_udpindatagrams()\n#define snmp_inc_udpnoports()\n#define snmp_inc_udpinerrors()\n#define snmp_inc_udpoutdatagrams()\n#define snmp_insert_udpidx_tree(pcb)\n#define snmp_delete_udpidx_tree(pcb)\n\n/* SNMP */\n#define snmp_inc_snmpinpkts()\n#define snmp_inc_snmpoutpkts()\n#define snmp_inc_snmpinbadversions()\n#define snmp_inc_snmpinbadcommunitynames()\n#define snmp_inc_snmpinbadcommunityuses()\n#define snmp_inc_snmpinasnparseerrs()\n#define snmp_inc_snmpintoobigs()\n#define snmp_inc_snmpinnosuchnames()\n#define snmp_inc_snmpinbadvalues()\n#define snmp_inc_snmpinreadonlys()\n#define snmp_inc_snmpingenerrs()\n#define snmp_add_snmpintotalreqvars(value)\n#define snmp_add_snmpintotalsetvars(value)\n#define snmp_inc_snmpingetrequests()\n#define snmp_inc_snmpingetnexts()\n#define snmp_inc_snmpinsetrequests()\n#define snmp_inc_snmpingetresponses()\n#define snmp_inc_snmpintraps()\n#define snmp_inc_snmpouttoobigs()\n#define snmp_inc_snmpoutnosuchnames()\n#define snmp_inc_snmpoutbadvalues()\n#define snmp_inc_snmpoutgenerrs()\n#define snmp_inc_snmpoutgetrequests()\n#define snmp_inc_snmpoutgetnexts()\n#define snmp_inc_snmpoutsetrequests()\n#define snmp_inc_snmpoutgetresponses()\n#define snmp_inc_snmpouttraps()\n#define snmp_get_snmpgrpid_ptr(oid)\n#define snmp_set_snmpenableauthentraps(value)\n#define snmp_get_snmpenableauthentraps(value)\n\n#endif /* LWIP_SNMP */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_SNMP_H__ */\n"
  },
  {
    "path": "app/include/lwip/snmp_asn1.h",
    "content": "/**\n * @file\n * Abstract Syntax Notation One (ISO 8824, 8825) codec.\n */\n \n/*\n * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * Author: Christiaan Simons <christiaan.simons@axon.tv>\n */\n\n#ifndef __LWIP_SNMP_ASN1_H__\n#define __LWIP_SNMP_ASN1_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/err.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/snmp.h\"\n\n#if LWIP_SNMP\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define SNMP_ASN1_UNIV   (0)    /* (!0x80 | !0x40) */\n#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 |  0x40) */\n#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */\n\n#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */\n#define SNMP_ASN1_PRIMIT (0)    /* (!0x20) */\n\n/* universal tags */\n#define SNMP_ASN1_INTEG  2\n#define SNMP_ASN1_OC_STR 4\n#define SNMP_ASN1_NUL    5\n#define SNMP_ASN1_OBJ_ID 6\n#define SNMP_ASN1_SEQ    16\n\n/* application specific (SNMP) tags */\n#define SNMP_ASN1_IPADDR 0    /* octet string size(4) */\n#define SNMP_ASN1_COUNTER 1   /* u32_t */\n#define SNMP_ASN1_GAUGE 2     /* u32_t */\n#define SNMP_ASN1_TIMETICKS 3 /* u32_t */\n#define SNMP_ASN1_OPAQUE 4    /* octet string */\n\n/* context specific (SNMP) tags */\n#define SNMP_ASN1_PDU_GET_REQ 0\n#define SNMP_ASN1_PDU_GET_NEXT_REQ 1\n#define SNMP_ASN1_PDU_GET_RESP 2\n#define SNMP_ASN1_PDU_SET_REQ 3\n#define SNMP_ASN1_PDU_TRAP 4\n\nerr_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type);\nerr_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length);\nerr_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value);\nerr_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value);\nerr_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid);\nerr_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw);\n\nvoid snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);\nvoid snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);\nvoid snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);\nvoid snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);\nerr_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);\nerr_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);\nerr_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value);\nerr_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value);\nerr_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);\nerr_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_SNMP */\n\n#endif /* __LWIP_SNMP_ASN1_H__ */\n"
  },
  {
    "path": "app/include/lwip/snmp_msg.h",
    "content": "/**\n * @file\n * SNMP Agent message handling structures.\n */\n\n/*\n * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * Author: Christiaan Simons <christiaan.simons@axon.tv>\n */\n\n#ifndef __LWIP_SNMP_MSG_H__\n#define __LWIP_SNMP_MSG_H__\n\n#include \"lwip/opt.h\"\n#include \"lwip/snmp.h\"\n#include \"lwip/snmp_structs.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/err.h\"\n\n#if LWIP_SNMP\n\n#if SNMP_PRIVATE_MIB\n/* When using a private MIB, you have to create a file 'private_mib.h' that contains\n * a 'struct mib_array_node mib_private' which contains your MIB. */\n#include \"private_mib.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* The listen port of the SNMP agent. Clients have to make their requests to\n   this port. Most standard clients won't work if you change this! */\n#ifndef SNMP_IN_PORT\n#define SNMP_IN_PORT 161\n#endif\n/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't\n   work if you change this! */\n#ifndef SNMP_TRAP_PORT\n#define SNMP_TRAP_PORT 162\n#endif\n\n#define SNMP_ES_NOERROR 0\n#define SNMP_ES_TOOBIG 1\n#define SNMP_ES_NOSUCHNAME 2\n#define SNMP_ES_BADVALUE 3\n#define SNMP_ES_READONLY 4\n#define SNMP_ES_GENERROR 5\n\n#define SNMP_GENTRAP_COLDSTART 0\n#define SNMP_GENTRAP_WARMSTART 1\n#define SNMP_GENTRAP_AUTHFAIL 4\n#define SNMP_GENTRAP_ENTERPRISESPC 6\n\nstruct snmp_varbind\n{\n  /* next pointer, NULL for last in list */\n  struct snmp_varbind *next;\n  /* previous pointer, NULL for first in list */\n  struct snmp_varbind *prev;\n\n  /* object identifier length (in s32_t) */\n  u8_t ident_len;\n  /* object identifier array */\n  s32_t *ident;\n\n  /* object value ASN1 type */\n  u8_t value_type;\n  /* object value length (in u8_t) */\n  u8_t value_len;\n  /* object value */\n  void *value;\n\n  /* encoding varbind seq length length */\n  u8_t seqlenlen;\n  /* encoding object identifier length length */\n  u8_t olenlen;\n  /* encoding object value length length */\n  u8_t vlenlen;\n  /* encoding varbind seq length */\n  u16_t seqlen;\n  /* encoding object identifier length */\n  u16_t olen;\n  /* encoding object value length */\n  u16_t vlen;\n};\n\nstruct snmp_varbind_root\n{\n  struct snmp_varbind *head;\n  struct snmp_varbind *tail;\n  /* number of variable bindings in list */\n  u8_t count;\n  /* encoding varbind-list seq length length */\n  u8_t seqlenlen;\n  /* encoding varbind-list seq length */\n  u16_t seqlen;\n};\n\n/** output response message header length fields */\nstruct snmp_resp_header_lengths\n{\n  /* encoding error-index length length */\n  u8_t erridxlenlen;\n  /* encoding error-status length length */\n  u8_t errstatlenlen;\n  /* encoding request id length length */\n  u8_t ridlenlen;\n  /* encoding pdu length length */\n  u8_t pdulenlen;\n  /* encoding community length length */\n  u8_t comlenlen;\n  /* encoding version length length */\n  u8_t verlenlen;\n  /* encoding sequence length length */\n  u8_t seqlenlen;\n\n  /* encoding error-index length */\n  u16_t erridxlen;\n  /* encoding error-status length */\n  u16_t errstatlen;\n  /* encoding request id length */\n  u16_t ridlen;\n  /* encoding pdu length */\n  u16_t pdulen;\n  /* encoding community length */\n  u16_t comlen;\n  /* encoding version length */\n  u16_t verlen;\n  /* encoding sequence length */\n  u16_t seqlen;\n};\n\n/** output response message header length fields */\nstruct snmp_trap_header_lengths\n{\n  /* encoding timestamp length length */\n  u8_t tslenlen;\n  /* encoding specific-trap length length */\n  u8_t strplenlen;\n  /* encoding generic-trap length length */\n  u8_t gtrplenlen;\n  /* encoding agent-addr length length */\n  u8_t aaddrlenlen;\n  /* encoding enterprise-id length length */\n  u8_t eidlenlen;\n  /* encoding pdu length length */\n  u8_t pdulenlen;\n  /* encoding community length length */\n  u8_t comlenlen;\n  /* encoding version length length */\n  u8_t verlenlen;\n  /* encoding sequence length length */\n  u8_t seqlenlen;\n\n  /* encoding timestamp length */\n  u16_t tslen;\n  /* encoding specific-trap length */\n  u16_t strplen;\n  /* encoding generic-trap length */\n  u16_t gtrplen;\n  /* encoding agent-addr length */\n  u16_t aaddrlen;\n  /* encoding enterprise-id length */\n  u16_t eidlen;\n  /* encoding pdu length */\n  u16_t pdulen;\n  /* encoding community length */\n  u16_t comlen;\n  /* encoding version length */\n  u16_t verlen;\n  /* encoding sequence length */\n  u16_t seqlen;\n};\n\n/* Accepting new SNMP messages. */\n#define SNMP_MSG_EMPTY                 0\n/* Search for matching object for variable binding. */\n#define SNMP_MSG_SEARCH_OBJ            1\n/* Perform SNMP operation on in-memory object.\n   Pass-through states, for symmetry only. */\n#define SNMP_MSG_INTERNAL_GET_OBJDEF   2\n#define SNMP_MSG_INTERNAL_GET_VALUE    3\n#define SNMP_MSG_INTERNAL_SET_TEST     4\n#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5\n#define SNMP_MSG_INTERNAL_SET_VALUE    6\n/* Perform SNMP operation on object located externally.\n   In theory this could be used for building a proxy agent.\n   Practical use is for an enterprise spc. app. gateway. */\n#define SNMP_MSG_EXTERNAL_GET_OBJDEF   7\n#define SNMP_MSG_EXTERNAL_GET_VALUE    8\n#define SNMP_MSG_EXTERNAL_SET_TEST     9\n#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10\n#define SNMP_MSG_EXTERNAL_SET_VALUE    11\n\n#define SNMP_COMMUNITY_STR_LEN 64\nstruct snmp_msg_pstat\n{\n  /* lwIP local port (161) binding */\n  struct udp_pcb *pcb;\n  /* source IP address */\n  ip_addr_t sip;\n  /* source UDP port */\n  u16_t sp;\n  /* request type */\n  u8_t rt;\n  /* request ID */\n  s32_t rid;\n  /* error status */\n  s32_t error_status;\n  /* error index */\n  s32_t error_index;\n  /* community name (zero terminated) */\n  u8_t community[SNMP_COMMUNITY_STR_LEN + 1];\n  /* community string length (exclusive zero term) */\n  u8_t com_strlen;\n  /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */\n  u8_t state;\n  /* saved arguments for MSG_EXTERNAL_x */\n  struct mib_external_node *ext_mib_node;\n  struct snmp_name_ptr ext_name_ptr;\n  struct obj_def ext_object_def;\n  struct snmp_obj_id ext_oid;\n  /* index into input variable binding list */\n  u8_t vb_idx;\n  /* ptr into input variable binding list */\n  struct snmp_varbind *vb_ptr;\n  /* list of variable bindings from input */\n  struct snmp_varbind_root invb;\n  /* list of variable bindings to output */\n  struct snmp_varbind_root outvb;\n  /* output response lengths used in ASN encoding */\n  struct snmp_resp_header_lengths rhl;\n};\n\nstruct snmp_msg_trap\n{\n  /* lwIP local port (161) binding */\n  struct udp_pcb *pcb;\n  /* destination IP address in network order */\n  ip_addr_t dip;\n\n  /* source enterprise ID (sysObjectID) */\n  struct snmp_obj_id *enterprise;\n  /* source IP address, raw network order format */\n  u8_t sip_raw[4];\n  /* generic trap code */\n  u32_t gen_trap;\n  /* specific trap code */\n  u32_t spc_trap;\n  /* timestamp */\n  u32_t ts;\n  /* list of variable bindings to output */\n  struct snmp_varbind_root outvb;\n  /* output trap lengths used in ASN encoding */\n  struct snmp_trap_header_lengths thl;\n};\n\n/** Agent Version constant, 0 = v1 oddity */\nextern const s32_t snmp_version;\n/** Agent default \"public\" community string */\nextern const char snmp_publiccommunity[7];\n\nextern struct snmp_msg_trap trap_msg;\n\n/** Agent setup, start listening to port 161. */\nvoid snmp_init(void);\nvoid snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);\nvoid snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst);\n\n/** Varbind-list functions. */\nstruct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);\nvoid snmp_varbind_free(struct snmp_varbind *vb);\nvoid snmp_varbind_list_free(struct snmp_varbind_root *root);\nvoid snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);\nstruct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);\n\n/** Handle an internal (recv) or external (private response) event. */\nvoid snmp_msg_event(u8_t request_id);\nerr_t snmp_send_response(struct snmp_msg_pstat *m_stat);\nerr_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap);\nvoid snmp_coldstart_trap(void);\nvoid snmp_authfail_trap(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_SNMP */\n\n#endif /* __LWIP_SNMP_MSG_H__ */\n"
  },
  {
    "path": "app/include/lwip/snmp_structs.h",
    "content": "/**\n * @file\n * Generic MIB tree structures.\n *\n * @todo namespace prefixes\n */\n\n/*\n * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * Author: Christiaan Simons <christiaan.simons@axon.tv>\n */\n\n#ifndef __LWIP_SNMP_STRUCTS_H__\n#define __LWIP_SNMP_STRUCTS_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/snmp.h\"\n\n#if SNMP_PRIVATE_MIB\n/* When using a private MIB, you have to create a file 'private_mib.h' that contains\n * a 'struct mib_array_node mib_private' which contains your MIB. */\n#include \"private_mib.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* MIB object instance */\n#define MIB_OBJECT_NONE 0 \n#define MIB_OBJECT_SCALAR 1\n#define MIB_OBJECT_TAB 2\n\n/* MIB access types */\n#define MIB_ACCESS_READ   1\n#define MIB_ACCESS_WRITE  2\n\n/* MIB object access */\n#define MIB_OBJECT_READ_ONLY      MIB_ACCESS_READ\n#define MIB_OBJECT_READ_WRITE     (MIB_ACCESS_READ | MIB_ACCESS_WRITE)\n#define MIB_OBJECT_WRITE_ONLY     MIB_ACCESS_WRITE\n#define MIB_OBJECT_NOT_ACCESSIBLE 0\n\n/** object definition returned by (get_object_def)() */\nstruct obj_def\n{\n  /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */\n  u8_t instance;\n  /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */\n  u8_t access;\n  /* ASN type for this object */\n  u8_t asn_type;\n  /* value length (host length) */\n  u16_t v_len;\n  /* length of instance part of supplied object identifier */\n  u8_t  id_inst_len;\n  /* instance part of supplied object identifier */\n  s32_t *id_inst_ptr;\n};\n\nstruct snmp_name_ptr\n{\n  u8_t ident_len;\n  s32_t *ident;\n};\n\n/** MIB const scalar (.0) node */\n#define MIB_NODE_SC 0x01\n/** MIB const array node */\n#define MIB_NODE_AR 0x02\n/** MIB array node (mem_malloced from RAM) */\n#define MIB_NODE_RA 0x03\n/** MIB list root node (mem_malloced from RAM) */\n#define MIB_NODE_LR 0x04\n/** MIB node for external objects */\n#define MIB_NODE_EX 0x05\n\n/** node \"base class\" layout, the mandatory fields for a node  */\nstruct mib_node\n{\n  /** returns struct obj_def for the given object identifier */\n  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\n  /** returns object value for the given object identifier,\n     @note the caller must allocate at least len bytes for the value */\n  void (*get_value)(struct obj_def *od, u16_t len, void *value);\n  /** tests length and/or range BEFORE setting */\n  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\n  /** sets object value, only to be called when set_test()  */\n  void (*set_value)(struct obj_def *od, u16_t len, void *value);  \n  /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */\n  u8_t node_type;\n  /* array or max list length */\n  u16_t maxlength;\n};\n\n/** derived node for scalars .0 index */\ntypedef struct mib_node mib_scalar_node;\n\n/** derived node, points to a fixed size const array\n    of sub-identifiers plus a 'child' pointer */\nstruct mib_array_node\n{\n  /* inherited \"base class\" members */\n  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\n  void (*get_value)(struct obj_def *od, u16_t len, void *value);\n  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\n  void (*set_value)(struct obj_def *od, u16_t len, void *value);\n\n  u8_t node_type;\n  u16_t maxlength;\n\n  /* additional struct members */\n  const s32_t *objid;\n  struct mib_node* const *nptr;\n};\n\n/** derived node, points to a fixed size mem_malloced array\n    of sub-identifiers plus a 'child' pointer */\nstruct mib_ram_array_node\n{\n  /* inherited \"base class\" members */\n  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\n  void (*get_value)(struct obj_def *od, u16_t len, void *value);\n  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\n  void (*set_value)(struct obj_def *od, u16_t len, void *value);\n\n  u8_t node_type;\n  u16_t maxlength;\n\n  /* aditional struct members */\n  s32_t *objid;\n  struct mib_node **nptr;\n};\n\nstruct mib_list_node\n{\n  struct mib_list_node *prev;  \n  struct mib_list_node *next;\n  s32_t objid;\n  struct mib_node *nptr;\n};\n\n/** derived node, points to a doubly linked list\n    of sub-identifiers plus a 'child' pointer */\nstruct mib_list_rootnode\n{\n  /* inherited \"base class\" members */\n  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\n  void (*get_value)(struct obj_def *od, u16_t len, void *value);\n  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\n  void (*set_value)(struct obj_def *od, u16_t len, void *value);\n\n  u8_t node_type;\n  u16_t maxlength;\n\n  /* additional struct members */\n  struct mib_list_node *head;\n  struct mib_list_node *tail;\n  /* counts list nodes in list  */\n  u16_t count;\n};\n\n/** derived node, has access functions for mib object in external memory or device\n    using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */\nstruct mib_external_node\n{\n  /* inherited \"base class\" members */\n  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\n  void (*get_value)(struct obj_def *od, u16_t len, void *value);\n  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\n  void (*set_value)(struct obj_def *od, u16_t len, void *value);\n\n  u8_t node_type;\n  u16_t maxlength;\n\n  /* additional struct members */\n  /** points to an external (in memory) record of some sort of addressing\n      information, passed to and interpreted by the funtions below */\n  void* addr_inf;\n  /** tree levels under this node */\n  u8_t tree_levels;\n  /** number of objects at this level */\n  u16_t (*level_length)(void* addr_inf, u8_t level);\n  /** compares object sub identifier with external id\n      return zero when equal, nonzero when unequal */\n  s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id);\n  void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id);\n\n  /** async Questions */\n  void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident);\n  void (*get_value_q)(u8_t rid, struct obj_def *od);\n  void (*set_test_q)(u8_t rid, struct obj_def *od);\n  void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value);\n  /** async Answers */\n  void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od);\n  void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\n  u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\n  void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\n  /** async Panic Close (agent returns error reply, \n      e.g. used for external transaction cleanup) */\n  void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident);\n  void (*get_value_pc)(u8_t rid, struct obj_def *od);\n  void (*set_test_pc)(u8_t rid, struct obj_def *od);\n  void (*set_value_pc)(u8_t rid, struct obj_def *od);\n};\n\n/** export MIB tree from mib2.c */\nextern const struct mib_array_node internet;\n\n/** dummy function pointers for non-leaf MIB nodes from mib2.c */\nvoid noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\nvoid noleafs_get_value(struct obj_def *od, u16_t len, void *value);\nu8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);\nvoid noleafs_set_value(struct obj_def *od, u16_t len, void *value);\n\nvoid snmp_oidtoip(s32_t *ident, ip_addr_t *ip);\nvoid snmp_iptooid(ip_addr_t *ip, s32_t *ident);\nvoid snmp_ifindextonetif(s32_t ifindex, struct netif **netif);\nvoid snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);\n\nstruct mib_list_node* snmp_mib_ln_alloc(s32_t id);\nvoid snmp_mib_ln_free(struct mib_list_node *ln);\nstruct mib_list_rootnode* snmp_mib_lrn_alloc(void);\nvoid snmp_mib_lrn_free(struct mib_list_rootnode *lrn);\n\ns8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn);\ns8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn);\nstruct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n);\n\nstruct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np);\nstruct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);\nu8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident);\nu8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_SNMP */\n\n#endif /* __LWIP_SNMP_STRUCTS_H__ */\n"
  },
  {
    "path": "app/include/lwip/sntp.h",
    "content": "#ifndef LWIP_SNTP_H\n#define LWIP_SNTP_H\n\n#include \"lwip/opt.h\"\n#include \"lwip/ip_addr.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** The maximum number of SNTP servers that can be set */\n#ifndef SNTP_MAX_SERVERS\n#define SNTP_MAX_SERVERS           3\n#endif\n\n/** Set this to 1 to implement the callback function called by dhcp when\n * NTP servers are received. */\n#ifndef SNTP_GET_SERVERS_FROM_DHCP\n#define SNTP_GET_SERVERS_FROM_DHCP 0//LWIP_DHCP_GET_NTP_SRV\n#endif\n\n/* Set this to 1 to support DNS names (or IP address strings) to set sntp servers */\n#ifndef SNTP_SERVER_DNS\n#define SNTP_SERVER_DNS            1\n#endif\n\n/** One server address/name can be defined as default if SNTP_SERVER_DNS == 1:\n * #define SNTP_SERVER_ADDRESS \"pool.ntp.org\"\n */\nuint32 sntp_get_current_timestamp();\nchar* sntp_get_real_time(long t);\n\nvoid sntp_init(void);\nvoid sntp_stop(void);\n\nsint8 sntp_get_timezone(void);\nbool sntp_set_timezone(sint8 timezone);\nvoid sntp_setserver(u8_t idx, ip_addr_t *addr);\nip_addr_t sntp_getserver(u8_t idx);\n\n#if SNTP_SERVER_DNS\nvoid sntp_setservername(u8_t idx, char *server);\nchar *sntp_getservername(u8_t idx);\n#endif /* SNTP_SERVER_DNS */\n\n#if SNTP_GET_SERVERS_FROM_DHCP\nvoid sntp_servermode_dhcp(int set_servers_from_dhcp);\n#else /* SNTP_GET_SERVERS_FROM_DHCP */\n#define sntp_servermode_dhcp(x)\n#endif /* SNTP_GET_SERVERS_FROM_DHCP */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_SNTP_H */\n"
  },
  {
    "path": "app/include/lwip/sockets.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n\n#ifndef __LWIP_SOCKETS_H__\n#define __LWIP_SOCKETS_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */\n\n#include <stddef.h> /* for size_t */\n\n#include \"lwip/ip_addr.h\"\n#include \"lwip/inet.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* members are in network byte order */\nstruct sockaddr_in {\n  u8_t sin_len;\n  u8_t sin_family;\n  u16_t sin_port;\n  struct in_addr sin_addr;\n  char sin_zero[8];\n};\n\nstruct sockaddr {\n  u8_t sa_len;\n  u8_t sa_family;\n  char sa_data[14];\n};\n\n#ifndef socklen_t\n#  define socklen_t u32_t\n#endif\n\n/* Socket protocol types (TCP/UDP/RAW) */\n#define SOCK_STREAM     1\n#define SOCK_DGRAM      2\n#define SOCK_RAW        3\n\n/*\n * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c)\n */\n#define  SO_DEBUG       0x0001 /* Unimplemented: turn on debugging info recording */\n#define  SO_ACCEPTCONN  0x0002 /* socket has had listen() */\n#define  SO_REUSEADDR   0x0004 /* Allow local address reuse */\n#define  SO_KEEPALIVE   0x0008 /* keep connections alive */\n#define  SO_DONTROUTE   0x0010 /* Unimplemented: just use interface addresses */\n#define  SO_BROADCAST   0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */\n#define  SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */\n#define  SO_LINGER      0x0080 /* linger on close if data present */\n#define  SO_OOBINLINE   0x0100 /* Unimplemented: leave received OOB data in line */\n#define  SO_REUSEPORT   0x0200 /* Unimplemented: allow local address & port reuse */\n\n#define SO_DONTLINGER   ((int)(~SO_LINGER))\n\n/*\n * Additional options, not kept in so_options.\n */\n#define SO_SNDBUF    0x1001    /* Unimplemented: send buffer size */\n#define SO_RCVBUF    0x1002    /* receive buffer size */\n#define SO_SNDLOWAT  0x1003    /* Unimplemented: send low-water mark */\n#define SO_RCVLOWAT  0x1004    /* Unimplemented: receive low-water mark */\n#define SO_SNDTIMEO  0x1005    /* Unimplemented: send timeout */\n#define SO_RCVTIMEO  0x1006    /* receive timeout */\n#define SO_ERROR     0x1007    /* get error status and clear */\n#define SO_TYPE      0x1008    /* get socket type */\n#define SO_CONTIMEO  0x1009    /* Unimplemented: connect timeout */\n#define SO_NO_CHECK  0x100a    /* don't create UDP checksum */\n\n\n/*\n * Structure used for manipulating linger option.\n */\nstruct linger {\n       int l_onoff;                /* option on/off */\n       int l_linger;               /* linger time */\n};\n\n/*\n * Level number for (get/set)sockopt() to apply to socket itself.\n */\n#define  SOL_SOCKET  0xfff    /* options for socket level */\n\n\n#define AF_UNSPEC       0\n#define AF_INET         2\n#define PF_INET         AF_INET\n#define PF_UNSPEC       AF_UNSPEC\n\n#define IPPROTO_IP      0\n#define IPPROTO_TCP     6\n#define IPPROTO_UDP     17\n#define IPPROTO_UDPLITE 136\n\n/* Flags we can use with send and recv. */\n#define MSG_PEEK       0x01    /* Peeks at an incoming message */\n#define MSG_WAITALL    0x02    /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */\n#define MSG_OOB        0x04    /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */\n#define MSG_DONTWAIT   0x08    /* Nonblocking i/o for this operation only */\n#define MSG_MORE       0x10    /* Sender will send more */\n\n\n/*\n * Options for level IPPROTO_IP\n */\n#define IP_TOS             1\n#define IP_TTL             2\n\n#if LWIP_TCP\n/*\n * Options for level IPPROTO_TCP\n */\n#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */\n#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */\n#define TCP_KEEPIDLE   0x03    /* set pcb->keep_idle  - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */\n#define TCP_KEEPINTVL  0x04    /* set pcb->keep_intvl - Use seconds for get/setsockopt */\n#define TCP_KEEPCNT    0x05    /* set pcb->keep_cnt   - Use number of probes sent for get/setsockopt */\n#endif /* LWIP_TCP */\n\n#if LWIP_UDP && LWIP_UDPLITE\n/*\n * Options for level IPPROTO_UDPLITE\n */\n#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */\n#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */\n#endif /* LWIP_UDP && LWIP_UDPLITE*/\n\n\n#if LWIP_IGMP\n/*\n * Options and types for UDP multicast traffic handling\n */\n#define IP_ADD_MEMBERSHIP  3\n#define IP_DROP_MEMBERSHIP 4\n#define IP_MULTICAST_TTL   5\n#define IP_MULTICAST_IF    6\n#define IP_MULTICAST_LOOP  7\n\ntypedef struct ip_mreq {\n    struct in_addr imr_multiaddr; /* IP multicast address of group */\n    struct in_addr imr_interface; /* local IP address of interface */\n} ip_mreq;\n#endif /* LWIP_IGMP */\n\n/*\n * The Type of Service provides an indication of the abstract\n * parameters of the quality of service desired.  These parameters are\n * to be used to guide the selection of the actual service parameters\n * when transmitting a datagram through a particular network.  Several\n * networks offer service precedence, which somehow treats high\n * precedence traffic as more important than other traffic (generally\n * by accepting only traffic above a certain precedence at time of high\n * load).  The major choice is a three way tradeoff between low-delay,\n * high-reliability, and high-throughput.\n * The use of the Delay, Throughput, and Reliability indications may\n * increase the cost (in some sense) of the service.  In many networks\n * better performance for one of these parameters is coupled with worse\n * performance on another.  Except for very unusual cases at most two\n * of these three indications should be set.\n */\n#define IPTOS_TOS_MASK          0x1E\n#define IPTOS_TOS(tos)          ((tos) & IPTOS_TOS_MASK)\n#define IPTOS_LOWDELAY          0x10\n#define IPTOS_THROUGHPUT        0x08\n#define IPTOS_RELIABILITY       0x04\n#define IPTOS_LOWCOST           0x02\n#define IPTOS_MINCOST           IPTOS_LOWCOST\n\n/*\n * The Network Control precedence designation is intended to be used\n * within a network only.  The actual use and control of that\n * designation is up to each network. The Internetwork Control\n * designation is intended for use by gateway control originators only.\n * If the actual use of these precedence designations is of concern to\n * a particular network, it is the responsibility of that network to\n * control the access to, and use of, those precedence designations.\n */\n#define IPTOS_PREC_MASK                 0xe0\n#define IPTOS_PREC(tos)                ((tos) & IPTOS_PREC_MASK)\n#define IPTOS_PREC_NETCONTROL           0xe0\n#define IPTOS_PREC_INTERNETCONTROL      0xc0\n#define IPTOS_PREC_CRITIC_ECP           0xa0\n#define IPTOS_PREC_FLASHOVERRIDE        0x80\n#define IPTOS_PREC_FLASH                0x60\n#define IPTOS_PREC_IMMEDIATE            0x40\n#define IPTOS_PREC_PRIORITY             0x20\n#define IPTOS_PREC_ROUTINE              0x00\n\n\n/*\n * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.\n * lwip_ioctl only supports FIONREAD and FIONBIO, for now\n *\n * Ioctl's have the command encoded in the lower word,\n * and the size of any in or out parameters in the upper\n * word.  The high 2 bits of the upper word are used\n * to encode the in/out status of the parameter; for now\n * we restrict parameters to at most 128 bytes.\n */\n#if !defined(FIONREAD) || !defined(FIONBIO)\n#define IOCPARM_MASK    0x7fU           /* parameters must be < 128 bytes */\n#define IOC_VOID        0x20000000UL    /* no parameters */\n#define IOC_OUT         0x40000000UL    /* copy out parameters */\n#define IOC_IN          0x80000000UL    /* copy in parameters */\n#define IOC_INOUT       (IOC_IN|IOC_OUT)\n                                        /* 0x20000000 distinguishes new &\n                                           old ioctl's */\n#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y))\n\n#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))\n\n#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))\n#endif /* !defined(FIONREAD) || !defined(FIONBIO) */\n\n#ifndef FIONREAD\n#define FIONREAD    _IOR('f', 127, unsigned long) /* get # bytes to read */\n#endif\n#ifndef FIONBIO\n#define FIONBIO     _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */\n#endif\n\n/* Socket I/O Controls: unimplemented */\n#ifndef SIOCSHIWAT\n#define SIOCSHIWAT  _IOW('s',  0, unsigned long)  /* set high watermark */\n#define SIOCGHIWAT  _IOR('s',  1, unsigned long)  /* get high watermark */\n#define SIOCSLOWAT  _IOW('s',  2, unsigned long)  /* set low watermark */\n#define SIOCGLOWAT  _IOR('s',  3, unsigned long)  /* get low watermark */\n#define SIOCATMARK  _IOR('s',  7, unsigned long)  /* at oob mark? */\n#endif\n\n/* commands for fnctl */\n#ifndef F_GETFL\n#define F_GETFL 3\n#endif\n#ifndef F_SETFL\n#define F_SETFL 4\n#endif\n\n/* File status flags and file access modes for fnctl,\n   these are bits in an int. */\n#ifndef O_NONBLOCK\n#define O_NONBLOCK  1 /* nonblocking I/O */\n#endif\n#ifndef O_NDELAY\n#define O_NDELAY    1 /* same as O_NONBLOCK, for compatibility */\n#endif\n\n#ifndef SHUT_RD\n  #define SHUT_RD   0\n  #define SHUT_WR   1\n  #define SHUT_RDWR 2\n#endif\n\n/* FD_SET used for lwip_select */\n#ifndef FD_SET\n  #undef  FD_SETSIZE\n  /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */\n  #define FD_SETSIZE    MEMP_NUM_NETCONN\n  #define FD_SET(n, p)  ((p)->fd_bits[(n)/8] |=  (1 << ((n) & 7)))\n  #define FD_CLR(n, p)  ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7)))\n  #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] &   (1 << ((n) & 7)))\n  #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p)))\n\n  typedef struct fd_set {\n          unsigned char fd_bits [(FD_SETSIZE+7)/8];\n        } fd_set;\n\n#endif /* FD_SET */\n\n/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided\n * by your system, set this to 0 and include <sys/time.h> in cc.h */ \n#ifndef LWIP_TIMEVAL_PRIVATE\n#define LWIP_TIMEVAL_PRIVATE 1\n#endif\n\n#if LWIP_TIMEVAL_PRIVATE\nstruct timeval {\n  long    tv_sec;         /* seconds */\n  long    tv_usec;        /* and microseconds */\n};\n#endif /* LWIP_TIMEVAL_PRIVATE */\n\nvoid lwip_socket_init(void);\n\nint lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);\nint lwip_bind(int s, const struct sockaddr *name, socklen_t namelen);\nint lwip_shutdown(int s, int how);\nint lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);\nint lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen);\nint lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen);\nint lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen);\nint lwip_close(int s);\nint lwip_connect(int s, const struct sockaddr *name, socklen_t namelen);\nint lwip_listen(int s, int backlog);\nint lwip_recv(int s, void *mem, size_t len, int flags);\nint lwip_read(int s, void *mem, size_t len);\nint lwip_recvfrom(int s, void *mem, size_t len, int flags,\n      struct sockaddr *from, socklen_t *fromlen);\nint lwip_send(int s, const void *dataptr, size_t size, int flags);\nint lwip_sendto(int s, const void *dataptr, size_t size, int flags,\n    const struct sockaddr *to, socklen_t tolen);\nint lwip_socket(int domain, int type, int protocol);\nint lwip_write(int s, const void *dataptr, size_t size);\nint lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,\n                struct timeval *timeout);\nint lwip_ioctl(int s, long cmd, void *argp);\nint lwip_fcntl(int s, int cmd, int val);\n\n#if LWIP_COMPAT_SOCKETS\n#define accept(a,b,c)         lwip_accept(a,b,c)\n#define bind(a,b,c)           lwip_bind(a,b,c)\n#define shutdown(a,b)         lwip_shutdown(a,b)\n#define closesocket(s)        lwip_close(s)\n#define connect(a,b,c)        lwip_connect(a,b,c)\n#define getsockname(a,b,c)    lwip_getsockname(a,b,c)\n#define getpeername(a,b,c)    lwip_getpeername(a,b,c)\n#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)\n#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)\n#define listen(a,b)           lwip_listen(a,b)\n#define recv(a,b,c,d)         lwip_recv(a,b,c,d)\n#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)\n#define send(a,b,c,d)         lwip_send(a,b,c,d)\n#define sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f)\n#define socket(a,b,c)         lwip_socket(a,b,c)\n#define select(a,b,c,d,e)     lwip_select(a,b,c,d,e)\n#define ioctlsocket(a,b,c)    lwip_ioctl(a,b,c)\n\n#if LWIP_POSIX_SOCKETS_IO_NAMES\n#define read(a,b,c)           lwip_read(a,b,c)\n#define write(a,b,c)          lwip_write(a,b,c)\n#define close(s)              lwip_close(s)\n#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */\n\n#endif /* LWIP_COMPAT_SOCKETS */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_SOCKET */\n\n#endif /* __LWIP_SOCKETS_H__ */\n"
  },
  {
    "path": "app/include/lwip/stats.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_STATS_H__\n#define __LWIP_STATS_H__\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/mem.h\"\n#include \"lwip/memp.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if LWIP_STATS\n\n#ifndef LWIP_STATS_LARGE\n#define LWIP_STATS_LARGE 0\n#endif\n\n#if LWIP_STATS_LARGE\n#define STAT_COUNTER     u32_t\n#define STAT_COUNTER_F   U32_F\n#else\n#define STAT_COUNTER     u16_t\n#define STAT_COUNTER_F   U16_F\n#endif \n\nstruct stats_proto {\n  STAT_COUNTER xmit;             /* Transmitted packets. */\n  STAT_COUNTER recv;             /* Received packets. */\n  STAT_COUNTER fw;               /* Forwarded packets. */\n  STAT_COUNTER drop;             /* Dropped packets. */\n  STAT_COUNTER chkerr;           /* Checksum error. */\n  STAT_COUNTER lenerr;           /* Invalid length error. */\n  STAT_COUNTER memerr;           /* Out of memory error. */\n  STAT_COUNTER rterr;            /* Routing error. */\n  STAT_COUNTER proterr;          /* Protocol error. */\n  STAT_COUNTER opterr;           /* Error in options. */\n  STAT_COUNTER err;              /* Misc error. */\n  STAT_COUNTER cachehit;\n};\n\nstruct stats_igmp {\n  STAT_COUNTER xmit;             /* Transmitted packets. */\n  STAT_COUNTER recv;             /* Received packets. */\n  STAT_COUNTER drop;             /* Dropped packets. */\n  STAT_COUNTER chkerr;           /* Checksum error. */\n  STAT_COUNTER lenerr;           /* Invalid length error. */\n  STAT_COUNTER memerr;           /* Out of memory error. */\n  STAT_COUNTER proterr;          /* Protocol error. */\n  STAT_COUNTER rx_v1;            /* Received v1 frames. */\n  STAT_COUNTER rx_group;         /* Received group-specific queries. */\n  STAT_COUNTER rx_general;       /* Received general queries. */\n  STAT_COUNTER rx_report;        /* Received reports. */\n  STAT_COUNTER tx_join;          /* Sent joins. */\n  STAT_COUNTER tx_leave;         /* Sent leaves. */\n  STAT_COUNTER tx_report;        /* Sent reports. */\n};\n\nstruct stats_mem {\n#ifdef LWIP_DEBUG\n  const char *name;\n#endif /* LWIP_DEBUG */\n  mem_size_t avail;\n  mem_size_t used;\n  mem_size_t max;\n  STAT_COUNTER err;\n  STAT_COUNTER illegal;\n};\n\nstruct stats_syselem {\n  STAT_COUNTER used;\n  STAT_COUNTER max;\n  STAT_COUNTER err;\n};\n\nstruct stats_sys {\n  struct stats_syselem sem;\n  struct stats_syselem mutex;\n  struct stats_syselem mbox;\n};\n\nstruct stats_ {\n#if LINK_STATS\n  struct stats_proto link;\n#endif\n#if ETHARP_STATS\n  struct stats_proto etharp;\n#endif\n#if IPFRAG_STATS\n  struct stats_proto ip_frag;\n#endif\n#if IP_STATS\n  struct stats_proto ip;\n#endif\n#if ICMP_STATS\n  struct stats_proto icmp;\n#endif\n#if IGMP_STATS\n  struct stats_igmp igmp;\n#endif\n#if UDP_STATS\n  struct stats_proto udp;\n#endif\n#if TCP_STATS\n  struct stats_proto tcp;\n#endif\n#if MEM_STATS\n  struct stats_mem mem;\n#endif\n#if MEMP_STATS\n  struct stats_mem memp[MEMP_MAX];\n#endif\n#if SYS_STATS\n  struct stats_sys sys;\n#endif\n};\n\nextern struct stats_ lwip_stats;\n\nvoid stats_init(void)ICACHE_FLASH_ATTR;\n\n#define STATS_INC(x) ++lwip_stats.x\n#define STATS_DEC(x) --lwip_stats.x\n#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \\\n                                if (lwip_stats.x.max < lwip_stats.x.used) { \\\n                                    lwip_stats.x.max = lwip_stats.x.used; \\\n                                } \\\n                             } while(0)\n#else /* LWIP_STATS */\n#define stats_init()\n#define STATS_INC(x)\n#define STATS_DEC(x)\n#define STATS_INC_USED(x)\n#endif /* LWIP_STATS */\n\n#if TCP_STATS\n#define TCP_STATS_INC(x) STATS_INC(x)\n#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, \"TCP\")\n#else\n#define TCP_STATS_INC(x)\n#define TCP_STATS_DISPLAY()\n#endif\n\n#if UDP_STATS\n#define UDP_STATS_INC(x) STATS_INC(x)\n#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, \"UDP\")\n#else\n#define UDP_STATS_INC(x)\n#define UDP_STATS_DISPLAY()\n#endif\n\n#if ICMP_STATS\n#define ICMP_STATS_INC(x) STATS_INC(x)\n#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, \"ICMP\")\n#else\n#define ICMP_STATS_INC(x)\n#define ICMP_STATS_DISPLAY()\n#endif\n\n#if IGMP_STATS\n#define IGMP_STATS_INC(x) STATS_INC(x)\n#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp)\n#else\n#define IGMP_STATS_INC(x)\n#define IGMP_STATS_DISPLAY()\n#endif\n\n#if IP_STATS\n#define IP_STATS_INC(x) STATS_INC(x)\n#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, \"IP\")\n#else\n#define IP_STATS_INC(x)\n#define IP_STATS_DISPLAY()\n#endif\n\n#if IPFRAG_STATS\n#define IPFRAG_STATS_INC(x) STATS_INC(x)\n#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, \"IP_FRAG\")\n#else\n#define IPFRAG_STATS_INC(x)\n#define IPFRAG_STATS_DISPLAY()\n#endif\n\n#if ETHARP_STATS\n#define ETHARP_STATS_INC(x) STATS_INC(x)\n#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, \"ETHARP\")\n#else\n#define ETHARP_STATS_INC(x)\n#define ETHARP_STATS_DISPLAY()\n#endif\n\n#if LINK_STATS\n#define LINK_STATS_INC(x) STATS_INC(x)\n#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, \"LINK\")\n#else\n#define LINK_STATS_INC(x)\n#define LINK_STATS_DISPLAY()\n#endif\n\n#if MEM_STATS\n#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y\n#define MEM_STATS_INC(x) STATS_INC(mem.x)\n#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y)\n#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y\n#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, \"HEAP\")\n#else\n#define MEM_STATS_AVAIL(x, y)\n#define MEM_STATS_INC(x)\n#define MEM_STATS_INC_USED(x, y)\n#define MEM_STATS_DEC_USED(x, y)\n#define MEM_STATS_DISPLAY()\n#endif\n\n#if MEMP_STATS\n#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y\n#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x)\n#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x)\n#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1)\n#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i)\n#else\n#define MEMP_STATS_AVAIL(x, i, y)\n#define MEMP_STATS_INC(x, i)\n#define MEMP_STATS_DEC(x, i)\n#define MEMP_STATS_INC_USED(x, i)\n#define MEMP_STATS_DISPLAY(i)\n#endif\n\n#if SYS_STATS\n#define SYS_STATS_INC(x) STATS_INC(sys.x)\n#define SYS_STATS_DEC(x) STATS_DEC(sys.x)\n#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1)\n#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys)\n#else\n#define SYS_STATS_INC(x)\n#define SYS_STATS_DEC(x)\n#define SYS_STATS_INC_USED(x)\n#define SYS_STATS_DISPLAY()\n#endif\n\n/* Display of statistics */\n#if LWIP_STATS_DISPLAY\nvoid stats_display(void)ICACHE_FLASH_ATTR;\nvoid stats_display_proto(struct stats_proto *proto, char *name)ICACHE_FLASH_ATTR;\nvoid stats_display_igmp(struct stats_igmp *igmp)ICACHE_FLASH_ATTR;\nvoid stats_display_mem(struct stats_mem *mem, char *name)ICACHE_FLASH_ATTR;\nvoid stats_display_memp(struct stats_mem *mem, int index)ICACHE_FLASH_ATTR;\nvoid stats_display_sys(struct stats_sys *sys)ICACHE_FLASH_ATTR;\n#else /* LWIP_STATS_DISPLAY */\n#define stats_display()\n#define stats_display_proto(proto, name)\n#define stats_display_igmp(igmp)\n#define stats_display_mem(mem, name)\n#define stats_display_memp(mem, index)\n#define stats_display_sys(sys)\n#endif /* LWIP_STATS_DISPLAY */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_STATS_H__ */\n"
  },
  {
    "path": "app/include/lwip/sys.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_SYS_H__\n#define __LWIP_SYS_H__\n\n#include \"lwip/opt.h\"\n\n#include \"eagle_soc.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if NO_SYS\n\n/* For a totally minimal and standalone system, we provide null\n   definitions of the sys_ functions. */\ntypedef u8_t sys_sem_t;\ntypedef u8_t sys_mutex_t;\ntypedef u8_t sys_mbox_t;\n\n#define sys_sem_new(s, c) ERR_OK\n#define sys_sem_signal(s)\n#define sys_sem_wait(s)\n#define sys_arch_sem_wait(s,t)\n#define sys_sem_free(s)\n#define sys_mutex_new(mu) ERR_OK\n#define sys_mutex_lock(mu)\n#define sys_mutex_unlock(mu)\n#define sys_mutex_free(mu)\n#define sys_mbox_new(m, s) ERR_OK\n#define sys_mbox_fetch(m,d)\n#define sys_mbox_tryfetch(m,d)\n#define sys_mbox_post(m,d)\n#define sys_mbox_trypost(m,d)\n#define sys_mbox_free(m)\n\n#define sys_thread_new(n,t,a,s,p)\n\n#define sys_msleep(t)\n\n#else /* NO_SYS */\n\n/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */\n#define SYS_ARCH_TIMEOUT 0xffffffffUL\n\n/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate.\n * For now we use the same magic value, but we allow this to change in future.\n */\n#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT \n\n#include \"lwip/err.h\"\n#include \"arch/sys_arch.h\"\n\n/** Function prototype for thread functions */\ntypedef void (*lwip_thread_fn)(void *arg);\n\n/* Function prototypes for functions to be implemented by platform ports\n   (in sys_arch.c) */\n\n/* Mutex functions: */\n\n/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores\n    should be used instead */\n#if LWIP_COMPAT_MUTEX\n/* for old ports that don't have mutexes: define them to binary semaphores */\n#define sys_mutex_t                   sys_sem_t\n#define sys_mutex_new(mutex)          sys_sem_new(mutex, 1)\n#define sys_mutex_lock(mutex)         sys_sem_wait(mutex)\n#define sys_mutex_unlock(mutex)       sys_sem_signal(mutex)\n#define sys_mutex_free(mutex)         sys_sem_free(mutex)\n#define sys_mutex_valid(mutex)        sys_sem_valid(mutex)\n#define sys_mutex_set_invalid(mutex)  sys_sem_set_invalid(mutex)\n\n#else /* LWIP_COMPAT_MUTEX */\n\n/** Create a new mutex\n * @param mutex pointer to the mutex to create\n * @return a new mutex */\nerr_t sys_mutex_new(sys_mutex_t *mutex);\n/** Lock a mutex\n * @param mutex the mutex to lock */\nvoid sys_mutex_lock(sys_mutex_t *mutex);\n/** Unlock a mutex\n * @param mutex the mutex to unlock */\nvoid sys_mutex_unlock(sys_mutex_t *mutex);\n/** Delete a semaphore\n * @param mutex the mutex to delete */\nvoid sys_mutex_free(sys_mutex_t *mutex); \n#ifndef sys_mutex_valid\n/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */\nint sys_mutex_valid(sys_mutex_t *mutex);\n#endif\n#ifndef sys_mutex_set_invalid\n/** Set a mutex invalid so that sys_mutex_valid returns 0 */\nvoid sys_mutex_set_invalid(sys_mutex_t *mutex);\n#endif\n#endif /* LWIP_COMPAT_MUTEX */\n\n/* Semaphore functions: */\n\n/** Create a new semaphore\n * @param sem pointer to the semaphore to create\n * @param count initial count of the semaphore\n * @return ERR_OK if successful, another err_t otherwise */\nerr_t sys_sem_new(sys_sem_t *sem, u8_t count);\n/** Signals a semaphore\n * @param sem the semaphore to signal */\nvoid sys_sem_signal(sys_sem_t *sem);\n/** Wait for a semaphore for the specified timeout\n * @param sem the semaphore to wait for\n * @param timeout timeout in milliseconds to wait (0 = wait forever)\n * @return time (in milliseconds) waited for the semaphore\n *         or SYS_ARCH_TIMEOUT on timeout */\nu32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout);\n/** Delete a semaphore\n * @param sem semaphore to delete */\nvoid sys_sem_free(sys_sem_t *sem);\n/** Wait for a semaphore - forever/no timeout */\n#define sys_sem_wait(sem)                  sys_arch_sem_wait(sem, 0)\n#ifndef sys_sem_valid\n/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */\nint sys_sem_valid(sys_sem_t *sem);\n#endif\n#ifndef sys_sem_set_invalid\n/** Set a semaphore invalid so that sys_sem_valid returns 0 */\nvoid sys_sem_set_invalid(sys_sem_t *sem);\n#endif\n\n/* Time functions. */\n#ifndef sys_msleep\nvoid sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */\n#endif\n\n/* Mailbox functions. */\n\n/** Create a new mbox of specified size\n * @param mbox pointer to the mbox to create\n * @param size (miminum) number of messages in this mbox\n * @return ERR_OK if successful, another err_t otherwise */\nerr_t sys_mbox_new(sys_mbox_t *mbox, int size);\n/** Post a message to an mbox - may not fail\n * -> blocks if full, only used from tasks not from ISR\n * @param mbox mbox to posts the message\n * @param msg message to post (ATTENTION: can be NULL) */\nvoid sys_mbox_post(sys_mbox_t *mbox, void *msg);\n/** Try to post a message to an mbox - may fail if full or ISR\n * @param mbox mbox to posts the message\n * @param msg message to post (ATTENTION: can be NULL) */\nerr_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg);\n/** Wait for a new message to arrive in the mbox\n * @param mbox mbox to get a message from\n * @param msg pointer where the message is stored\n * @param timeout maximum time (in milliseconds) to wait for a message\n * @return time (in milliseconds) waited for a message, may be 0 if not waited\n           or SYS_ARCH_TIMEOUT on timeout\n *         The returned time has to be accurate to prevent timer jitter! */\nu32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout);\n/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */\n#ifndef sys_arch_mbox_tryfetch\n/** Wait for a new message to arrive in the mbox\n * @param mbox mbox to get a message from\n * @param msg pointer where the message is stored\n * @param timeout maximum time (in milliseconds) to wait for a message\n * @return 0 (milliseconds) if a message has been received\n *         or SYS_MBOX_EMPTY if the mailbox is empty */\nu32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg);\n#endif\n/** For now, we map straight to sys_arch implementation. */\n#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)\n/** Delete an mbox\n * @param mbox mbox to delete */\nvoid sys_mbox_free(sys_mbox_t *mbox);\n#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0)\n#ifndef sys_mbox_valid\n/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */\nint sys_mbox_valid(sys_mbox_t *mbox);\n#endif\n#ifndef sys_mbox_set_invalid\n/** Set an mbox invalid so that sys_mbox_valid returns 0 */\nvoid sys_mbox_set_invalid(sys_mbox_t *mbox);\n#endif\n\n/** The only thread function:\n * Creates a new thread\n * @param name human-readable name for the thread (used for debugging purposes)\n * @param thread thread-function\n * @param arg parameter passed to 'thread'\n * @param stacksize stack size in bytes for the new thread (may be ignored by ports)\n * @param prio priority of the new thread (may be ignored by ports) */\nsys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio);\n\n#endif /* NO_SYS */\n\n/* sys_init() must be called before anthing else. */\nvoid sys_init(void)ICACHE_FLASH_ATTR;\n\n#ifndef sys_jiffies\n/** Ticks/jiffies since power up. */\nu32_t sys_jiffies(void)ICACHE_FLASH_ATTR;\n#endif\n\n/** Returns the current time in milliseconds,\n * may be the same as sys_jiffies or at least based on it. */\nstatic inline u32_t sys_now(void) ICACHE_FLASH_ATTR;\nstatic inline u32_t sys_now(void)\n{\n\treturn NOW()/(TIMER_CLK_FREQ/1000);\n}\n\n/* Critical Region Protection */\n/* These functions must be implemented in the sys_arch.c file.\n   In some implementations they can provide a more light-weight protection\n   mechanism than using semaphores. Otherwise semaphores can be used for\n   implementation */\n#ifndef SYS_ARCH_PROTECT\n/** SYS_LIGHTWEIGHT_PROT\n * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection\n * for certain critical regions during buffer allocation, deallocation and memory\n * allocation and deallocation.\n */\n#if SYS_LIGHTWEIGHT_PROT\n\n/** SYS_ARCH_DECL_PROTECT\n * declare a protection variable. This macro will default to defining a variable of\n * type sys_prot_t. If a particular port needs a different implementation, then\n * this macro may be defined in sys_arch.h.\n */\n#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev\n/** SYS_ARCH_PROTECT\n * Perform a \"fast\" protect. This could be implemented by\n * disabling interrupts for an embedded system or by using a semaphore or\n * mutex. The implementation should allow calling SYS_ARCH_PROTECT when\n * already protected. The old protection level is returned in the variable\n * \"lev\". This macro will default to calling the sys_arch_protect() function\n * which should be implemented in sys_arch.c. If a particular port needs a\n * different implementation, then this macro may be defined in sys_arch.h\n */\n#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()\n/** SYS_ARCH_UNPROTECT\n * Perform a \"fast\" set of the protection level to \"lev\". This could be\n * implemented by setting the interrupt level to \"lev\" within the MACRO or by\n * using a semaphore or mutex.  This macro will default to calling the\n * sys_arch_unprotect() function which should be implemented in\n * sys_arch.c. If a particular port needs a different implementation, then\n * this macro may be defined in sys_arch.h\n */\n#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)\nsys_prot_t sys_arch_protect(void)ICACHE_FLASH_ATTR;\nvoid sys_arch_unprotect(sys_prot_t pval)ICACHE_FLASH_ATTR;\n\n#else\n\n#define SYS_ARCH_DECL_PROTECT(lev)\n#define SYS_ARCH_PROTECT(lev) lev = ets_intr_lock()\t//fix by ives at 2014.3.24\n#define SYS_ARCH_UNPROTECT(lev) lev = ets_intr_unlock()\n\n#endif /* SYS_LIGHTWEIGHT_PROT */\n\n#endif /* SYS_ARCH_PROTECT */\n\n/*\n * Macros to set/get and increase/decrease variables in a thread-safe way.\n * Use these for accessing variable that are used from more than one thread.\n */\n\n#ifndef SYS_ARCH_INC\n#define SYS_ARCH_INC(var, val) do { \\\n                                SYS_ARCH_DECL_PROTECT(old_level); \\\n                                SYS_ARCH_PROTECT(old_level); \\\n                                var += val; \\\n                                SYS_ARCH_UNPROTECT(old_level); \\\n                              } while(0)\n#endif /* SYS_ARCH_INC */\n\n#ifndef SYS_ARCH_DEC\n#define SYS_ARCH_DEC(var, val) do { \\\n                                SYS_ARCH_DECL_PROTECT(old_level); \\\n                                SYS_ARCH_PROTECT(old_level); \\\n                                var -= val; \\\n                                SYS_ARCH_UNPROTECT(old_level); \\\n                              } while(0)\n#endif /* SYS_ARCH_DEC */\n\n#ifndef SYS_ARCH_GET\n#define SYS_ARCH_GET(var, ret) do { \\\n                                SYS_ARCH_DECL_PROTECT(old_level); \\\n                                SYS_ARCH_PROTECT(old_level); \\\n                                ret = var; \\\n                                SYS_ARCH_UNPROTECT(old_level); \\\n                              } while(0)\n#endif /* SYS_ARCH_GET */\n\n#ifndef SYS_ARCH_SET\n#define SYS_ARCH_SET(var, val) do { \\\n                                SYS_ARCH_DECL_PROTECT(old_level); \\\n                                SYS_ARCH_PROTECT(old_level); \\\n                                var = val; \\\n                                SYS_ARCH_UNPROTECT(old_level); \\\n                              } while(0)\n#endif /* SYS_ARCH_SET */\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __LWIP_SYS_H__ */\n"
  },
  {
    "path": "app/include/lwip/tcp.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_TCP_H__\n#define __LWIP_TCP_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/sys.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/icmp.h\"\n#include \"lwip/err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct tcp_pcb;\n\n/** Function prototype for tcp accept callback functions. Called when a new\n * connection can be accepted on a listening pcb.\n *\n * @param arg Additional argument to pass to the callback function (@see tcp_arg())\n * @param newpcb The new connection pcb\n * @param err An error code if there has been an error accepting.\n *            Only return ERR_ABRT if you have called tcp_abort from within the\n *            callback function!\n */\ntypedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err);\n\n/** Function prototype for tcp receive callback functions. Called when data has\n * been received.\n *\n * @param arg Additional argument to pass to the callback function (@see tcp_arg())\n * @param tpcb The connection pcb which received data\n * @param p The received data (or NULL when the connection has been closed!)\n * @param err An error code if there has been an error receiving\n *            Only return ERR_ABRT if you have called tcp_abort from within the\n *            callback function!\n */\ntypedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb,\n                             struct pbuf *p, err_t err);\n\n/** Function prototype for tcp sent callback functions. Called when sent data has\n * been acknowledged by the remote side. Use it to free corresponding resources.\n * This also means that the pcb has now space available to send new data.\n *\n * @param arg Additional argument to pass to the callback function (@see tcp_arg())\n * @param tpcb The connection pcb for which data has been acknowledged\n * @param len The amount of bytes acknowledged\n * @return ERR_OK: try to send some data by calling tcp_output\n *            Only return ERR_ABRT if you have called tcp_abort from within the\n *            callback function!\n */\ntypedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb,\n                              u16_t len);\n\n/** Function prototype for tcp poll callback functions. Called periodically as\n * specified by @see tcp_poll.\n *\n * @param arg Additional argument to pass to the callback function (@see tcp_arg())\n * @param tpcb tcp pcb\n * @return ERR_OK: try to send some data by calling tcp_output\n *            Only return ERR_ABRT if you have called tcp_abort from within the\n *            callback function!\n */\ntypedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb);\n\n/** Function prototype for tcp error callback functions. Called when the pcb\n * receives a RST or is unexpectedly closed for any other reason.\n *\n * @note The corresponding pcb is already freed when this callback is called!\n *\n * @param arg Additional argument to pass to the callback function (@see tcp_arg())\n * @param err Error code to indicate why the pcb has been closed\n *            ERR_ABRT: aborted through tcp_abort or by a TCP timer\n *            ERR_RST: the connection was reset by the remote host\n */\ntypedef void  (*tcp_err_fn)(void *arg, err_t err);\n\n/** Function prototype for tcp connected callback functions. Called when a pcb\n * is connected to the remote side after initiating a connection attempt by\n * calling tcp_connect().\n *\n * @param arg Additional argument to pass to the callback function (@see tcp_arg())\n * @param tpcb The connection pcb which is connected\n * @param err An unused error code, always ERR_OK currently ;-) TODO!\n *            Only return ERR_ABRT if you have called tcp_abort from within the\n *            callback function!\n *\n * @note When a connection attempt fails, the error callback is currently called!\n */\ntypedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err);\n\nenum tcp_state {\n  CLOSED      = 0,\n  LISTEN      = 1,\n  SYN_SENT    = 2,\n  SYN_RCVD    = 3,\n  ESTABLISHED = 4,\n  FIN_WAIT_1  = 5,\n  FIN_WAIT_2  = 6,\n  CLOSE_WAIT  = 7,\n  CLOSING     = 8,\n  LAST_ACK    = 9,\n  TIME_WAIT   = 10\n};\n\n#if LWIP_CALLBACK_API\n  /* Function to call when a listener has been connected.\n   * @param arg user-supplied argument (tcp_pcb.callback_arg)\n   * @param pcb a new tcp_pcb that now is connected\n   * @param err an error argument (TODO: that is current always ERR_OK?)\n   * @return ERR_OK: accept the new connection,\n   *                 any other err_t abortsthe new connection\n   */\n#define DEF_ACCEPT_CALLBACK  tcp_accept_fn accept;\n#else /* LWIP_CALLBACK_API */\n#define DEF_ACCEPT_CALLBACK\n#endif /* LWIP_CALLBACK_API */\n\n/**\n * members common to struct tcp_pcb and struct tcp_listen_pcb\n */\n#define TCP_PCB_COMMON(type) \\\n  type *next; /* for the linked list */ \\\n  enum tcp_state state; /* TCP state */ \\\n  u8_t prio; \\\n  void *callback_arg; \\\n  /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \\\n  DEF_ACCEPT_CALLBACK \\\n  /* ports are in host byte order */ \\\n  u16_t local_port\n\n\n/* the TCP protocol control block */\nstruct tcp_pcb {\n/** common PCB members */\n  IP_PCB;\n/** protocol specific PCB members */\n  TCP_PCB_COMMON(struct tcp_pcb);\n\n  /* ports are in host byte order */\n  u16_t remote_port;\n  \n  u8_t flags;\n#define TF_ACK_DELAY   ((u8_t)0x01U)   /* Delayed ACK. */\n#define TF_ACK_NOW     ((u8_t)0x02U)   /* Immediate ACK. */\n#define TF_INFR        ((u8_t)0x04U)   /* In fast recovery. */\n#define TF_TIMESTAMP   ((u8_t)0x08U)   /* Timestamp option enabled */\n#define TF_RXCLOSED    ((u8_t)0x10U)   /* rx closed by tcp_shutdown */\n#define TF_FIN         ((u8_t)0x20U)   /* Connection was closed locally (FIN segment enqueued). */\n#define TF_NODELAY     ((u8_t)0x40U)   /* Disable Nagle algorithm */\n#define TF_NAGLEMEMERR ((u8_t)0x80U)   /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */\n\n  /* the rest of the fields are in host byte order\n     as we have to do some math with them */\n  /* receiver variables */\n  u32_t rcv_nxt;   /* next seqno expected */\n  u16_t rcv_wnd;   /* receiver window available */\n  u16_t rcv_ann_wnd; /* receiver window to announce */\n  u32_t rcv_ann_right_edge; /* announced right edge of window */\n\n  /* Timers */\n  u32_t tmr;\n  u8_t polltmr, pollinterval;\n  \n  /* Retransmission timer. */\n  s16_t rtime;\n  \n  u16_t mss;   /* maximum segment size */\n  \n  /* RTT (round trip time) estimation variables */\n  u32_t rttest; /* RTT estimate in 500ms ticks */\n  u32_t rtseq;  /* sequence number being timed */\n  s16_t sa, sv; /* @todo document this */\n\n  s16_t rto;    /* retransmission time-out */\n  u8_t nrtx;    /* number of retransmissions */\n\n  /* fast retransmit/recovery */\n  u32_t lastack; /* Highest acknowledged seqno. */\n  u8_t dupacks;\n  \n  /* congestion avoidance/control variables */\n  u16_t cwnd;  \n  u16_t ssthresh;\n\n  /* sender variables */\n  u32_t snd_nxt;   /* next new seqno to be sent */\n  u16_t snd_wnd;   /* sender window */\n  u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last\n                             window update. */\n  u32_t snd_lbb;       /* Sequence number of next byte to be buffered. */\n\n  u16_t acked;\n  \n  u16_t snd_buf;   /* Available buffer space for sending (in bytes). */\n#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3)\n  u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */\n\n#if TCP_OVERSIZE\n  /* Extra bytes available at the end of the last pbuf in unsent. */\n  u16_t unsent_oversize;\n#endif /* TCP_OVERSIZE */ \n\n  /* These are ordered by sequence number: */\n  struct tcp_seg *unsent;   /* Unsent (queued) segments. */\n  struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */\n#if TCP_QUEUE_OOSEQ  \n  struct tcp_seg *ooseq;    /* Received out of sequence segments. */\n#endif /* TCP_QUEUE_OOSEQ */\n\n  struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */\n\n#if LWIP_CALLBACK_API\n  /* Function to be called when more send buffer space is available. */\n  tcp_sent_fn sent;\n  /* Function to be called when (in-sequence) data has arrived. */\n  tcp_recv_fn recv;\n  /* Function to be called when a connection has been set up. */\n  tcp_connected_fn connected;\n  /* Function which is called periodically. */\n  tcp_poll_fn poll;\n  /* Function to be called whenever a fatal error occurs. */\n  tcp_err_fn errf;\n#endif /* LWIP_CALLBACK_API */\n\n#if LWIP_TCP_TIMESTAMPS\n  u32_t ts_lastacksent;\n  u32_t ts_recent;\n#endif /* LWIP_TCP_TIMESTAMPS */\n\n  /* idle time before KEEPALIVE is sent */\n  u32_t keep_idle;\n#if LWIP_TCP_KEEPALIVE\n  u32_t keep_intvl;\n  u32_t keep_cnt;\n#endif /* LWIP_TCP_KEEPALIVE */\n  \n  /* Persist timer counter */\n  u32_t persist_cnt;\n  /* Persist timer back-off */\n  u8_t persist_backoff;\n\n  /* KEEPALIVE counter */\n  u8_t keep_cnt_sent;\n};\n\nstruct tcp_pcb_listen {  \n/* Common members of all PCB types */\n  IP_PCB;\n/* Protocol specific PCB members */\n  TCP_PCB_COMMON(struct tcp_pcb_listen);\n\n#if TCP_LISTEN_BACKLOG\n  u8_t backlog;\n  u8_t accepts_pending;\n#endif /* TCP_LISTEN_BACKLOG */\n};\n\n#if LWIP_EVENT_API\n\nenum lwip_event {\n  LWIP_EVENT_ACCEPT,\n  LWIP_EVENT_SENT,\n  LWIP_EVENT_RECV,\n  LWIP_EVENT_CONNECTED,\n  LWIP_EVENT_POLL,\n  LWIP_EVENT_ERR\n};\n\nerr_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,\n         enum lwip_event,\n         struct pbuf *p,\n         u16_t size,\n         err_t err);\n\n#endif /* LWIP_EVENT_API */\n\n/* Application program's interface: */\nstruct tcp_pcb * tcp_new     (void)ICACHE_FLASH_ATTR;\n\nvoid             tcp_arg     (struct tcp_pcb *pcb, void *arg) ICACHE_FLASH_ATTR;\nvoid             tcp_accept  (struct tcp_pcb *pcb, tcp_accept_fn accept) ICACHE_FLASH_ATTR;\nvoid             tcp_recv    (struct tcp_pcb *pcb, tcp_recv_fn recv) ICACHE_FLASH_ATTR;\nvoid             tcp_sent    (struct tcp_pcb *pcb, tcp_sent_fn sent)ICACHE_FLASH_ATTR;\nvoid             tcp_poll    (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)ICACHE_FLASH_ATTR;\nvoid             tcp_err     (struct tcp_pcb *pcb, tcp_err_fn err)ICACHE_FLASH_ATTR;\n\n#define          tcp_mss(pcb)             (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12)  : (pcb)->mss)\n#define          tcp_sndbuf(pcb)          ((pcb)->snd_buf)\n#define          tcp_sndqueuelen(pcb)     ((pcb)->snd_queuelen)\n#define          tcp_nagle_disable(pcb)   ((pcb)->flags |= TF_NODELAY)\n#define          tcp_nagle_enable(pcb)    ((pcb)->flags &= ~TF_NODELAY)\n#define          tcp_nagle_disabled(pcb)  (((pcb)->flags & TF_NODELAY) != 0)\n\n#if TCP_LISTEN_BACKLOG\n#define          tcp_accepted(pcb) do { \\\n  LWIP_ASSERT(\"pcb->state == LISTEN (called for wrong pcb?)\", pcb->state == LISTEN); \\\n  (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0)\n#else  /* TCP_LISTEN_BACKLOG */\n#define          tcp_accepted(pcb) LWIP_ASSERT(\"pcb->state == LISTEN (called for wrong pcb?)\", \\\n                                               pcb->state == LISTEN)\n#endif /* TCP_LISTEN_BACKLOG */\n\nvoid             tcp_recved  (struct tcp_pcb *pcb, u16_t len)ICACHE_FLASH_ATTR;\nerr_t            tcp_bind    (struct tcp_pcb *pcb, ip_addr_t *ipaddr,\n                              u16_t port)ICACHE_FLASH_ATTR;\nerr_t            tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr,\n                              u16_t port, tcp_connected_fn connected)ICACHE_FLASH_ATTR;\n\nstruct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)ICACHE_FLASH_ATTR;\n#define          tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)\n\nvoid             tcp_abort (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nerr_t            tcp_close   (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nerr_t            tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)ICACHE_FLASH_ATTR;\n\n/* Flags for \"apiflags\" parameter in tcp_write */\n#define TCP_WRITE_FLAG_COPY 0x01\n#define TCP_WRITE_FLAG_MORE 0x02\n\nerr_t            tcp_write   (struct tcp_pcb *pcb, const void *dataptr, u16_t len,\n                              u8_t apiflags)ICACHE_FLASH_ATTR;\n\nvoid             tcp_setprio (struct tcp_pcb *pcb, u8_t prio)ICACHE_FLASH_ATTR;\n\n#define TCP_PRIO_MIN    1\n#define TCP_PRIO_NORMAL 64\n#define TCP_PRIO_MAX    127\n\nextern err_t            tcp_output(struct tcp_pcb *pcb);\n\n\nconst char* tcp_debug_state_str(enum tcp_state s)ICACHE_FLASH_ATTR;\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_TCP */\n\n#endif /* __LWIP_TCP_H__ */\n"
  },
  {
    "path": "app/include/lwip/tcp_impl.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_TCP_IMPL_H__\n#define __LWIP_TCP_IMPL_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/tcp.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/icmp.h\"\n#include \"lwip/err.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Functions for interfacing with TCP: */\n\n/* Lower layer interface to TCP: */\n#define tcp_init() /* Compatibility define, no init needed. */\nvoid             tcp_tmr     (void)ICACHE_FLASH_ATTR;  /* Must be called every\n                                         TCP_TMR_INTERVAL\n                                         ms. (Typically 250 ms). */\n/* It is also possible to call these two functions at the right\n   intervals (instead of calling tcp_tmr()). */\nvoid             tcp_slowtmr (void)ICACHE_FLASH_ATTR;\nvoid             tcp_fasttmr (void)ICACHE_FLASH_ATTR;\n\n\n/* Only used by IP to pass a TCP segment to TCP: */\nvoid             tcp_input   (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR;\n/* Used within the TCP code only: */\nstruct tcp_pcb * tcp_alloc   (u8_t prio)ICACHE_FLASH_ATTR;\nvoid             tcp_abandon (struct tcp_pcb *pcb, int reset)ICACHE_FLASH_ATTR;\nerr_t            tcp_send_empty_ack(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nvoid             tcp_rexmit  (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nvoid             tcp_rexmit_rto  (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nvoid             tcp_rexmit_fast (struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nu32_t            tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\n\n/**\n * This is the Nagle algorithm: try to combine user data to send as few TCP\n * segments as possible. Only send if\n * - no previously transmitted data on the connection remains unacknowledged or\n * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or\n * - the only unsent segment is at least pcb->mss bytes long (or there is more\n *   than one unsent segment - with lwIP, this can happen although unsent->len < mss)\n * - or if we are in fast-retransmit (TF_INFR)\n */\n#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \\\n                            ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \\\n                            (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \\\n                              ((tpcb)->unsent->len >= (tpcb)->mss))) \\\n                            ) ? 1 : 0)\n#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)\n\n\n#define TCP_SEQ_LT(a,b)     ((s32_t)((a)-(b)) < 0)\n#define TCP_SEQ_LEQ(a,b)    ((s32_t)((a)-(b)) <= 0)\n#define TCP_SEQ_GT(a,b)     ((s32_t)((a)-(b)) > 0)\n#define TCP_SEQ_GEQ(a,b)    ((s32_t)((a)-(b)) >= 0)\n/* is b<=a<=c? */\n#if 0 /* see bug #10548 */\n#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))\n#endif\n#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))\n#define TCP_FIN 0x01U\n#define TCP_SYN 0x02U\n#define TCP_RST 0x04U\n#define TCP_PSH 0x08U\n#define TCP_ACK 0x10U\n#define TCP_URG 0x20U\n#define TCP_ECE 0x40U\n#define TCP_CWR 0x80U\n\n#define TCP_FLAGS 0x3fU\n\n/* Length of the TCP header, excluding options. */\n#define TCP_HLEN 20\n\n#ifndef TCP_TMR_INTERVAL\n#define TCP_TMR_INTERVAL       125  /* The TCP timer interval in milliseconds. */\n#endif /* TCP_TMR_INTERVAL */\n\n#ifndef TCP_FAST_INTERVAL\n#define TCP_FAST_INTERVAL      TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */\n#endif /* TCP_FAST_INTERVAL */\n\n#ifndef TCP_SLOW_INTERVAL\n#define TCP_SLOW_INTERVAL      (2*TCP_TMR_INTERVAL)  /* the coarse grained timeout in milliseconds */\n#endif /* TCP_SLOW_INTERVAL */\n\n#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */\n#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */\n\n#define TCP_OOSEQ_TIMEOUT        6U /* x RTO */\n\n#ifndef TCP_MSL\n#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */\n#endif\n\n/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */\n#ifndef  TCP_KEEPIDLE_DEFAULT\n#define  TCP_KEEPIDLE_DEFAULT     120000UL /* Default KEEPALIVE timer in milliseconds */\n#endif\n\n#ifndef  TCP_KEEPINTVL_DEFAULT\n#define  TCP_KEEPINTVL_DEFAULT    10000UL   /* Default Time between KEEPALIVE probes in milliseconds */\n#endif\n\n#ifndef  TCP_KEEPCNT_DEFAULT\n#define  TCP_KEEPCNT_DEFAULT      9U        /* Default Counter for KEEPALIVE probes */\n#endif\n\n#define  TCP_MAXIDLE              TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT  /* Maximum KEEPALIVE probe time */\n\n/* Fields are (of course) in network byte order.\n * Some fields are converted to host byte order in tcp_input().\n */\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct tcp_hdr {\n  PACK_STRUCT_FIELD(u16_t src);\t\t\t\t//Դ�˿�\n  PACK_STRUCT_FIELD(u16_t dest);\t\t\t\t//Ŀ�Ķ˿�\n  PACK_STRUCT_FIELD(u32_t seqno);\t\t\t//���\n  PACK_STRUCT_FIELD(u32_t ackno);\t\t\t//Ӧ�����\n  PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);//�ײ�����+����λ+��־λ\n  PACK_STRUCT_FIELD(u16_t wnd);\t\t\t\t//���ڴ�С\n  PACK_STRUCT_FIELD(u16_t chksum);\t\t\t//У���\n  PACK_STRUCT_FIELD(u16_t urgp);\t\t\t\t//����ָ��\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)\n#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)\n#define TCPH_FLAGS(phdr)  (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)\n\n#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))\n#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))\n#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags))\n#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags))\n\n#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags))\n#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )\n\n#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0))\n\n/** Flags used on input processing, not on pcb->flags\n*/\n#define TF_RESET     (u8_t)0x08U   /* Connection was reset. */\n#define TF_CLOSED    (u8_t)0x10U   /* Connection was sucessfully closed. */\n#define TF_GOT_FIN   (u8_t)0x20U   /* Connection was closed by the remote end. */\n\n\n#if LWIP_EVENT_API\n\n#define TCP_EVENT_ACCEPT(pcb,err,ret)    ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\\n                LWIP_EVENT_ACCEPT, NULL, 0, err)\n#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\\n                   LWIP_EVENT_SENT, NULL, space, ERR_OK)\n#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\\n                LWIP_EVENT_RECV, (p), 0, (err))\n#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\\n                LWIP_EVENT_RECV, NULL, 0, ERR_OK)\n#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\\n                LWIP_EVENT_CONNECTED, NULL, 0, (err))\n#define TCP_EVENT_POLL(pcb,ret)       ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\\n                LWIP_EVENT_POLL, NULL, 0, ERR_OK)\n#define TCP_EVENT_ERR(errf,arg,err)  lwip_tcp_event((arg), NULL, \\\n                LWIP_EVENT_ERR, NULL, 0, (err))\n\n#else /* LWIP_EVENT_API */\n\n#define TCP_EVENT_ACCEPT(pcb,err,ret)                          \\\n  do {                                                         \\\n    if((pcb)->accept != NULL)                                  \\\n      (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err));  \\\n    else (ret) = ERR_ARG;                                      \\\n  } while (0)\n\n#define TCP_EVENT_SENT(pcb,space,ret)                          \\\n  do {                                                         \\\n    if((pcb)->sent != NULL)                                    \\\n      (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space));  \\\n    else (ret) = ERR_OK;                                       \\\n  } while (0)\n\n#define TCP_EVENT_RECV(pcb,p,err,ret)                          \\\n  do {                                                         \\\n    if((pcb)->recv != NULL) {                                  \\\n      (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\\\n    } else {                                                   \\\n      (ret) = tcp_recv_null(NULL, (pcb), (p), (err));          \\\n    }                                                          \\\n  } while (0)\n\n#define TCP_EVENT_CLOSED(pcb,ret)                                \\\n  do {                                                           \\\n    if(((pcb)->recv != NULL)) {                                  \\\n      (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\\\n    } else {                                                     \\\n      (ret) = ERR_OK;                                            \\\n    }                                                            \\\n  } while (0)\n\n#define TCP_EVENT_CONNECTED(pcb,err,ret)                         \\\n  do {                                                           \\\n    if((pcb)->connected != NULL)                                 \\\n      (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \\\n    else (ret) = ERR_OK;                                         \\\n  } while (0)\n\n#define TCP_EVENT_POLL(pcb,ret)                                \\\n  do {                                                         \\\n    if((pcb)->poll != NULL)                                    \\\n      (ret) = (pcb)->poll((pcb)->callback_arg,(pcb));          \\\n    else (ret) = ERR_OK;                                       \\\n  } while (0)\n\n#define TCP_EVENT_ERR(errf,arg,err)                            \\\n  do {                                                         \\\n    if((errf) != NULL)                                         \\\n      (errf)((arg),(err));                                     \\\n  } while (0)\n\n#endif /* LWIP_EVENT_API */\n\n/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */\n#if TCP_OVERSIZE && defined(LWIP_DEBUG)\n#define TCP_OVERSIZE_DBGCHECK 1\n#else\n#define TCP_OVERSIZE_DBGCHECK 0\n#endif\n\n/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */\n#define TCP_CHECKSUM_ON_COPY  (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP)\n\n/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */\nstruct tcp_seg {\n  struct tcp_seg *next;    /* used when putting segements on a queue */\n  struct pbuf *p;          /* buffer containing data + TCP header */\n  void *dataptr;           /* pointer to the TCP data in the pbuf */\n  u16_t len;               /* the TCP length of this segment */\n#if TCP_OVERSIZE_DBGCHECK\n  u16_t oversize_left;     /* Extra bytes available at the end of the last\n                              pbuf in unsent (used for asserting vs.\n                              tcp_pcb.unsent_oversized only) */\n#endif /* TCP_OVERSIZE_DBGCHECK */ \n#if TCP_CHECKSUM_ON_COPY\n  u16_t chksum;\n  u8_t  chksum_swapped;\n#endif /* TCP_CHECKSUM_ON_COPY */\n  u8_t  flags;\n#define TF_SEG_OPTS_MSS         (u8_t)0x01U /* Include MSS option. */\n#define TF_SEG_OPTS_TS          (u8_t)0x02U /* Include timestamp option. */\n#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is\n                                               checksummed into 'chksum' */\n  struct tcp_hdr *tcphdr;  /* the TCP header */\n};\n\n#define LWIP_TCP_OPT_LENGTH(flags)              \\\n  (flags & TF_SEG_OPTS_MSS ? 4  : 0) +          \\\n  (flags & TF_SEG_OPTS_TS  ? 12 : 0)\n\n/** This returns a TCP header option for MSS in an u32_t */\n#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) |          \\\n                                               ((u32_t)4 << 16) |          \\\n                                               (((u32_t)TCP_MSS / 256) << 8) | \\\n                                               (TCP_MSS & 255))\n\n/* Global variables: */\nextern struct tcp_pcb *tcp_input_pcb;\nextern u32_t tcp_ticks;\n\n/* The TCP PCB lists. */\nunion tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */\n  struct tcp_pcb_listen *listen_pcbs; \n  struct tcp_pcb *pcbs;\n};\nextern struct tcp_pcb *tcp_bound_pcbs;\nextern union tcp_listen_pcbs_t tcp_listen_pcbs;\nextern struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a\n              state in which they accept or send\n              data. */\nextern struct tcp_pcb *tcp_tw_pcbs;      /* List of all TCP PCBs in TIME-WAIT. */\n\nextern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */\n\n/* Axioms about the above lists:   \n   1) Every TCP PCB that is not CLOSED is in one of the lists.\n   2) A PCB is only in one of the lists.\n   3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.\n   4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.\n*/\n/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB\n   with a PCB list or removes a PCB from a list, respectively. */\n#ifndef TCP_DEBUG_PCB_LISTS\n#define TCP_DEBUG_PCB_LISTS 0\n#endif\n#if TCP_DEBUG_PCB_LISTS\n#define TCP_REG(pcbs, npcb) do {\\\n                            LWIP_DEBUGF(TCP_DEBUG, (\"TCP_REG %p local port %d\\n\", (npcb), (npcb)->local_port)); \\\n                            for(tcp_tmp_pcb = *(pcbs); \\\n          tcp_tmp_pcb != NULL; \\\n        tcp_tmp_pcb = tcp_tmp_pcb->next) { \\\n                                LWIP_ASSERT(\"TCP_REG: already registered\\n\", tcp_tmp_pcb != (npcb)); \\\n                            } \\\n                            LWIP_ASSERT(\"TCP_REG: pcb->state != CLOSED\", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \\\n                            (npcb)->next = *(pcbs); \\\n                            LWIP_ASSERT(\"TCP_REG: npcb->next != npcb\", (npcb)->next != (npcb)); \\\n                            *(pcbs) = (npcb); \\\n                            LWIP_ASSERT(\"TCP_RMV: tcp_pcbs sane\", tcp_pcbs_sane()); \\\n              tcp_timer_needed(); \\\n                            } while(0)\n#define TCP_RMV(pcbs, npcb) do { \\\n                            LWIP_ASSERT(\"TCP_RMV: pcbs != NULL\", *(pcbs) != NULL); \\\n                            LWIP_DEBUGF(TCP_DEBUG, (\"TCP_RMV: removing %p from %p\\n\", (npcb), *(pcbs))); \\\n                            if(*(pcbs) == (npcb)) { \\\n                               *(pcbs) = (*pcbs)->next; \\\n                            } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \\\n                               if(tcp_tmp_pcb->next == (npcb)) { \\\n                                  tcp_tmp_pcb->next = (npcb)->next; \\\n                                  break; \\\n                               } \\\n                            } \\\n                            (npcb)->next = NULL; \\\n                            LWIP_ASSERT(\"TCP_RMV: tcp_pcbs sane\", tcp_pcbs_sane()); \\\n                            LWIP_DEBUGF(TCP_DEBUG, (\"TCP_RMV: removed %p from %p\\n\", (npcb), *(pcbs))); \\\n                            } while(0)\n\n#else /* LWIP_DEBUG */\n\n#define TCP_REG(pcbs, npcb)                        \\\n  do {                                             \\\n    (npcb)->next = *pcbs;                          \\\n    *(pcbs) = (npcb);                              \\\n    tcp_timer_needed();                            \\\n  } while (0)\n\n#define TCP_RMV(pcbs, npcb)                        \\\n  do {                                             \\\n    if(*(pcbs) == (npcb)) {                        \\\n      (*(pcbs)) = (*pcbs)->next;                   \\\n    }                                              \\\n    else {                                         \\\n      for(tcp_tmp_pcb = *pcbs;                     \\\n          tcp_tmp_pcb != NULL;                     \\\n          tcp_tmp_pcb = tcp_tmp_pcb->next) {       \\\n        if(tcp_tmp_pcb->next == (npcb)) {          \\\n          tcp_tmp_pcb->next = (npcb)->next;        \\\n          break;                                   \\\n        }                                          \\\n      }                                            \\\n    }                                              \\\n    (npcb)->next = NULL;                           \\\n  } while(0)\n\n#endif /* LWIP_DEBUG */\n\n\n/* Internal functions: */\nstruct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nvoid tcp_pcb_purge(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nvoid tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\n\nvoid tcp_segs_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR;\nvoid tcp_seg_free(struct tcp_seg *seg)ICACHE_FLASH_ATTR;\nstruct tcp_seg *tcp_seg_copy(struct tcp_seg *seg)ICACHE_FLASH_ATTR;\n\n#define tcp_ack(pcb)                               \\\n  do {                                             \\\n    if((pcb)->flags & TF_ACK_DELAY) {              \\\n      (pcb)->flags &= ~TF_ACK_DELAY;               \\\n      (pcb)->flags |= TF_ACK_NOW;                  \\\n    }                                              \\\n    else {                                         \\\n      (pcb)->flags |= TF_ACK_DELAY;                \\\n    }                                              \\\n  } while (0)\n\n#define tcp_ack_now(pcb)                           \\\n  do {                                             \\\n    (pcb)->flags |= TF_ACK_NOW;                    \\\n  } while (0)\n\nerr_t tcp_send_fin(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nerr_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)ICACHE_FLASH_ATTR;\n\nvoid tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg)ICACHE_FLASH_ATTR;\n\nvoid tcp_rst(u32_t seqno, u32_t ackno,\n       ip_addr_t *local_ip, ip_addr_t *remote_ip,\n       u16_t local_port, u16_t remote_port)ICACHE_FLASH_ATTR;\n\nu32_t tcp_next_iss(void)ICACHE_FLASH_ATTR;\n\nvoid tcp_keepalive(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nvoid tcp_zero_window_probe(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\n\n#if TCP_CALCULATE_EFF_SEND_MSS\nu16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)ICACHE_FLASH_ATTR;\n#endif /* TCP_CALCULATE_EFF_SEND_MSS */\n\n#if LWIP_CALLBACK_API\nerr_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)ICACHE_FLASH_ATTR;\n#endif /* LWIP_CALLBACK_API */\n\n#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG\nvoid tcp_debug_print(struct tcp_hdr *tcphdr)ICACHE_FLASH_ATTR;\nvoid tcp_debug_print_flags(u8_t flags)ICACHE_FLASH_ATTR;\nvoid tcp_debug_print_state(enum tcp_state s)ICACHE_FLASH_ATTR;\nvoid tcp_debug_print_pcbs(void)ICACHE_FLASH_ATTR;\ns16_t tcp_pcbs_sane(void)ICACHE_FLASH_ATTR;\n#else\n#  define tcp_debug_print(tcphdr)\n#  define tcp_debug_print_flags(flags)\n#  define tcp_debug_print_state(s)\n#  define tcp_debug_print_pcbs()\n#  define tcp_pcbs_sane() 1\n#endif /* TCP_DEBUG */\n\n/** External function (implemented in timers.c), called when TCP detects\n * that a timer is needed (i.e. active- or time-wait-pcb found). */\nvoid tcp_timer_needed(void)ICACHE_FLASH_ATTR;\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_TCP */\n\n#endif /* __LWIP_TCP_H__ */\n"
  },
  {
    "path": "app/include/lwip/tcpip.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_TCPIP_H__\n#define __LWIP_TCPIP_H__\n\n#include \"lwip/opt.h\"\n\n#if !NO_SYS /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/api_msg.h\"\n#include \"lwip/netifapi.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/api.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/timers.h\"\n#include \"lwip/netif.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/** Define this to something that triggers a watchdog. This is called from\n * tcpip_thread after processing a message. */\n#ifndef LWIP_TCPIP_THREAD_ALIVE\n#define LWIP_TCPIP_THREAD_ALIVE()\n#endif\n\n#if LWIP_TCPIP_CORE_LOCKING\n/** The global semaphore to lock the stack. */\nextern sys_mutex_t lock_tcpip_core;\n#define LOCK_TCPIP_CORE()     sys_mutex_lock(&lock_tcpip_core)\n#define UNLOCK_TCPIP_CORE()   sys_mutex_unlock(&lock_tcpip_core)\n#define TCPIP_APIMSG(m)       tcpip_apimsg_lock(m)\n#define TCPIP_APIMSG_ACK(m)\n#define TCPIP_NETIFAPI(m)     tcpip_netifapi_lock(m)\n#define TCPIP_NETIFAPI_ACK(m)\n#else /* LWIP_TCPIP_CORE_LOCKING */\n#define LOCK_TCPIP_CORE()\n#define UNLOCK_TCPIP_CORE()\n#define TCPIP_APIMSG(m)       tcpip_apimsg(m)\n#define TCPIP_APIMSG_ACK(m)   sys_sem_signal(&m->conn->op_completed)\n#define TCPIP_NETIFAPI(m)     tcpip_netifapi(m)\n#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem)\n#endif /* LWIP_TCPIP_CORE_LOCKING */\n\n/** Function prototype for the init_done function passed to tcpip_init */\ntypedef void (*tcpip_init_done_fn)(void *arg);\n/** Function prototype for functions passed to tcpip_callback() */\ntypedef void (*tcpip_callback_fn)(void *ctx);\n\nvoid tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg);\n\n#if LWIP_NETCONN\nerr_t tcpip_apimsg(struct api_msg *apimsg);\n#if LWIP_TCPIP_CORE_LOCKING\nerr_t tcpip_apimsg_lock(struct api_msg *apimsg);\n#endif /* LWIP_TCPIP_CORE_LOCKING */\n#endif /* LWIP_NETCONN */\n\nerr_t tcpip_input(struct pbuf *p, struct netif *inp);\n\n#if LWIP_NETIF_API\nerr_t tcpip_netifapi(struct netifapi_msg *netifapimsg);\n#if LWIP_TCPIP_CORE_LOCKING\nerr_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);\n#endif /* LWIP_TCPIP_CORE_LOCKING */\n#endif /* LWIP_NETIF_API */\n\nerr_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block);\n#define tcpip_callback(f, ctx)              tcpip_callback_with_block(f, ctx, 1)\n\n/* free pbufs or heap memory from another context without blocking */\nerr_t pbuf_free_callback(struct pbuf *p);\nerr_t mem_free_callback(void *m);\n\n#if LWIP_TCPIP_TIMEOUT\nerr_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg);\nerr_t tcpip_untimeout(sys_timeout_handler h, void *arg);\n#endif /* LWIP_TCPIP_TIMEOUT */\n\nenum tcpip_msg_type {\n#if LWIP_NETCONN\n  TCPIP_MSG_API,\n#endif /* LWIP_NETCONN */\n  TCPIP_MSG_INPKT,\n#if LWIP_NETIF_API\n  TCPIP_MSG_NETIFAPI,\n#endif /* LWIP_NETIF_API */\n#if LWIP_TCPIP_TIMEOUT\n  TCPIP_MSG_TIMEOUT,\n  TCPIP_MSG_UNTIMEOUT,\n#endif /* LWIP_TCPIP_TIMEOUT */\n  TCPIP_MSG_CALLBACK\n};\n\nstruct tcpip_msg {\n  enum tcpip_msg_type type;\n  sys_sem_t *sem;\n  union {\n#if LWIP_NETCONN\n    struct api_msg *apimsg;\n#endif /* LWIP_NETCONN */\n#if LWIP_NETIF_API\n    struct netifapi_msg *netifapimsg;\n#endif /* LWIP_NETIF_API */\n    struct {\n      struct pbuf *p;\n      struct netif *netif;\n    } inp;\n    struct {\n      tcpip_callback_fn function;\n      void *ctx;\n    } cb;\n#if LWIP_TCPIP_TIMEOUT\n    struct {\n      u32_t msecs;\n      sys_timeout_handler h;\n      void *arg;\n    } tmo;\n#endif /* LWIP_TCPIP_TIMEOUT */\n  } msg;\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* !NO_SYS */\n\n#endif /* __LWIP_TCPIP_H__ */\n"
  },
  {
    "path": "app/include/lwip/timers.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *         Simon Goldschmidt\n *\n */\n#ifndef __LWIP_TIMERS_H__\n#define __LWIP_TIMERS_H__\n\n#include \"lwip/opt.h\"\n\n/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */\n#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS))\n\n#if LWIP_TIMERS\n\n#include \"lwip/err.h\"\n#include \"lwip/sys.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef LWIP_DEBUG_TIMERNAMES\n#ifdef LWIP_DEBUG\n#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG\n#else /* LWIP_DEBUG */\n#define LWIP_DEBUG_TIMERNAMES 0\n#endif /* LWIP_DEBUG*/\n#endif\n\n/** Function prototype for a timeout callback function. Register such a function\n * using sys_timeout().\n *\n * @param arg Additional argument to pass to the function - set up by sys_timeout()\n */\ntypedef void (* sys_timeout_handler)(void *arg);\n\nstruct sys_timeo {\n  struct sys_timeo *next;\n  u32_t time;\n  sys_timeout_handler h;\n  void *arg;\n#if LWIP_DEBUG_TIMERNAMES\n  const char* handler_name;\n#endif /* LWIP_DEBUG_TIMERNAMES */\n};\n\nvoid sys_timeouts_init(void)ICACHE_FLASH_ATTR;\n\n#if LWIP_DEBUG_TIMERNAMES\nvoid sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)ICACHE_FLASH_ATTR;\n#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler)\n#else /* LWIP_DEBUG_TIMERNAMES */\nvoid sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR;\n#endif /* LWIP_DEBUG_TIMERNAMES */\n\nvoid sys_untimeout(sys_timeout_handler handler, void *arg)ICACHE_FLASH_ATTR;\n#if NO_SYS\nvoid sys_check_timeouts(void)ICACHE_FLASH_ATTR;\nvoid sys_restart_timeouts(void)ICACHE_FLASH_ATTR;\n#else /* NO_SYS */\nvoid sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg);\n#endif /* NO_SYS */\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_TIMERS */\n#endif /* __LWIP_TIMERS_H__ */\n"
  },
  {
    "path": "app/include/lwip/udp.h",
    "content": "/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIP_UDP_H__\n#define __LWIP_UDP_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/pbuf.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/ip.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define UDP_HLEN 8\n\n/* Fields are (of course) in network byte order. */\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct udp_hdr {\n  PACK_STRUCT_FIELD(u16_t src);\n  PACK_STRUCT_FIELD(u16_t dest);  /* src/dest UDP ports */\n  PACK_STRUCT_FIELD(u16_t len);\n  PACK_STRUCT_FIELD(u16_t chksum);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#define UDP_FLAGS_NOCHKSUM       0x01U\n#define UDP_FLAGS_UDPLITE        0x02U\n#define UDP_FLAGS_CONNECTED      0x04U\n#define UDP_FLAGS_MULTICAST_LOOP 0x08U\n\nstruct udp_pcb;\n\n/** Function prototype for udp pcb receive callback functions\n * addr and port are in same byte order as in the pcb\n * The callback is responsible for freeing the pbuf\n * if it's not used any more.\n *\n * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf\n *            makes 'addr' invalid, too.\n *\n * @param arg user supplied argument (udp_pcb.recv_arg)\n * @param pcb the udp_pcb which received data\n * @param p the packet buffer that was received\n * @param addr the remote IP address from which the packet was received\n * @param port the remote port from which the packet was received\n */\ntypedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,\n    ip_addr_t *addr, u16_t port);\n\n\nstruct udp_pcb {\n/* Common members of all PCB types */\n  IP_PCB;\n\n/* Protocol specific PCB members */\n\n  struct udp_pcb *next;\n\n  u8_t flags;\n  /** ports are in host byte order */\n  u16_t local_port, remote_port;\n\n#if LWIP_IGMP\n  /** outgoing network interface for multicast packets */\n  ip_addr_t multicast_ip;\n#endif /* LWIP_IGMP */\n\n#if LWIP_UDPLITE\n  /** used for UDP_LITE only */\n  u16_t chksum_len_rx, chksum_len_tx;\n#endif /* LWIP_UDPLITE */\n\n  /** receive callback function */\n  udp_recv_fn recv;\n  /** user-supplied argument for the recv callback */\n  void *recv_arg;  \n};\n/* udp_pcbs export for exernal reference (e.g. SNMP agent) */\nextern struct udp_pcb *udp_pcbs;\n\n/* The following functions is the application layer interface to the\n   UDP code. */\nstruct udp_pcb * udp_new        (void)ICACHE_FLASH_ATTR;\nvoid             udp_remove     (struct udp_pcb *pcb)ICACHE_FLASH_ATTR;\nerr_t            udp_bind       (struct udp_pcb *pcb, ip_addr_t *ipaddr,\n                                 u16_t port)ICACHE_FLASH_ATTR;\nerr_t            udp_connect    (struct udp_pcb *pcb, ip_addr_t *ipaddr,\n                                 u16_t port)ICACHE_FLASH_ATTR;\nvoid             udp_disconnect (struct udp_pcb *pcb)ICACHE_FLASH_ATTR;\nvoid             udp_recv       (struct udp_pcb *pcb, udp_recv_fn recv,\n                                 void *recv_arg)ICACHE_FLASH_ATTR;\nerr_t            udp_sendto_if  (struct udp_pcb *pcb, struct pbuf *p,\n                                 ip_addr_t *dst_ip, u16_t dst_port,\n                                 struct netif *netif)ICACHE_FLASH_ATTR;\nerr_t            udp_sendto     (struct udp_pcb *pcb, struct pbuf *p,\n                                 ip_addr_t *dst_ip, u16_t dst_port)ICACHE_FLASH_ATTR;\nerr_t            udp_send       (struct udp_pcb *pcb, struct pbuf *p)ICACHE_FLASH_ATTR;\n\n#if LWIP_CHECKSUM_ON_COPY\nerr_t            udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p,\n                                 ip_addr_t *dst_ip, u16_t dst_port,\n                                 struct netif *netif, u8_t have_chksum,\n                                 u16_t chksum)ICACHE_FLASH_ATTR;\nerr_t            udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p,\n                                 ip_addr_t *dst_ip, u16_t dst_port,\n                                 u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR;\nerr_t            udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,\n                                 u8_t have_chksum, u16_t chksum)ICACHE_FLASH_ATTR;\n#endif /* LWIP_CHECKSUM_ON_COPY */\n\n#define          udp_flags(pcb) ((pcb)->flags)\n#define          udp_setflags(pcb, f)  ((pcb)->flags = (f))\n\n/* The following functions are the lower layer interface to UDP. */\nvoid             udp_input      (struct pbuf *p, struct netif *inp)ICACHE_FLASH_ATTR;\n\n#define udp_init() /* Compatibility define, not init needed. */\n\n#if UDP_DEBUG\nvoid udp_debug_print(struct udp_hdr *udphdr)ICACHE_FLASH_ATTR;\n#else\n#define udp_debug_print(udphdr)\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* LWIP_UDP */\n\n#endif /* __LWIP_UDP_H__ */\n"
  },
  {
    "path": "app/include/lwipopts.h",
    "content": "/**\n * @file\n *\n * lwIP Options Configuration\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n#ifndef __LWIPOPTS_H__\n#define __LWIPOPTS_H__\n\n\n/*\n   -----------------------------------------------\n   ---------- Platform specific locking ----------\n   -----------------------------------------------\n*/\n\n/**\n * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain\n * critical regions during buffer allocation, deallocation and memory\n * allocation and deallocation.\n */\n#ifndef SYS_LIGHTWEIGHT_PROT\n#define SYS_LIGHTWEIGHT_PROT            0\n#endif\n\n/** \n * NO_SYS==1: Provides VERY minimal functionality. Otherwise,\n * use lwIP facilities.\n */\n#ifndef NO_SYS\n#define NO_SYS                          1\n#endif\n\n/**\n * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1\n * Mainly for compatibility to old versions.\n */\n#ifndef NO_SYS_NO_TIMERS\n#define NO_SYS_NO_TIMERS                0\n#endif\n\n/**\n * MEMCPY: override this if you have a faster implementation at hand than the\n * one included in your C library\n */\n#ifndef MEMCPY\n#define MEMCPY(dst,src,len)             os_memcpy(dst,src,len)\n#endif\n\n/**\n * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a\n * call to memcpy() if the length is known at compile time and is small.\n */\n#ifndef SMEMCPY\n#define SMEMCPY(dst,src,len)            os_memcpy(dst,src,len)\n#endif\n\n/*\n   ------------------------------------\n   ---------- Memory options ----------\n   ------------------------------------\n*/\n/**\n * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library\n * instead of the lwip internal allocator. Can save code size if you\n * already use it.\n */\n#ifndef MEM_LIBC_MALLOC\n#define MEM_LIBC_MALLOC                 1\n#endif\n\n/**\n* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator.\n* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution\n* speed and usage from interrupts!\n*/\n#ifndef MEMP_MEM_MALLOC\n#define MEMP_MEM_MALLOC                 1\n#endif\n\n/**\n * MEM_ALIGNMENT: should be set to the alignment of the CPU\n *    4 byte alignment -> #define MEM_ALIGNMENT 4\n *    2 byte alignment -> #define MEM_ALIGNMENT 2\n */\n#ifndef MEM_ALIGNMENT\n#define MEM_ALIGNMENT                   4\n#endif\n\n/**\n * MEM_SIZE: the size of the heap memory. If the application will send\n * a lot of data that needs to be copied, this should be set high.\n */\n#ifndef MEM_SIZE\n#define MEM_SIZE                        16000\n#endif\n\n/**\n * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array.\n * This can be used to individually change the location of each pool.\n * Default is one big array for all pools\n */\n#ifndef MEMP_SEPARATE_POOLS\n#define MEMP_SEPARATE_POOLS             1\n#endif\n\n/**\n * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable\n * amount of bytes before and after each memp element in every pool and fills\n * it with a prominent default value.\n *    MEMP_OVERFLOW_CHECK == 0 no checking\n *    MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed\n *    MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time\n *      memp_malloc() or memp_free() is called (useful but slow!)\n */\n#ifndef MEMP_OVERFLOW_CHECK\n#define MEMP_OVERFLOW_CHECK             0\n#endif\n\n/**\n * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make\n * sure that there are no cycles in the linked lists.\n */\n#ifndef MEMP_SANITY_CHECK\n#define MEMP_SANITY_CHECK               1\n#endif\n\n/**\n * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set\n * of memory pools of various sizes. When mem_malloc is called, an element of\n * the smallest pool that can provide the length needed is returned.\n * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled.\n */\n#ifndef MEM_USE_POOLS\n#define MEM_USE_POOLS                   0\n#endif\n\n/**\n * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next\n * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more\n * reliable. */\n#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL\n#define MEM_USE_POOLS_TRY_BIGGER_POOL   0\n#endif\n\n/**\n * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h\n * that defines additional pools beyond the \"standard\" ones required\n * by lwIP. If you set this to 1, you must have lwippools.h in your \n * inlude path somewhere. \n */\n#ifndef MEMP_USE_CUSTOM_POOLS\n#define MEMP_USE_CUSTOM_POOLS           0\n#endif\n\n/**\n * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from\n * interrupt context (or another context that doesn't allow waiting for a\n * semaphore).\n * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT,\n * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs\n * with each loop so that mem_free can run.\n *\n * ATTENTION: As you can see from the above description, this leads to dis-/\n * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc\n * can need longer.\n *\n * If you don't want that, at least for NO_SYS=0, you can still use the following\n * functions to enqueue a deallocation call which then runs in the tcpip_thread\n * context:\n * - pbuf_free_callback(p);\n * - mem_free_callback(m);\n */\n#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0\n#endif\n\n/*\n   ------------------------------------------------\n   ---------- Internal Memory Pool Sizes ----------\n   ------------------------------------------------\n*/\n/**\n * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF).\n * If the application sends a lot of data out of ROM (or other static memory),\n * this should be set high.\n */\n#ifndef MEMP_NUM_PBUF\n#define MEMP_NUM_PBUF                   10\n#endif\n\n/**\n * MEMP_NUM_RAW_PCB: Number of raw connection PCBs\n * (requires the LWIP_RAW option)\n */\n#ifndef MEMP_NUM_RAW_PCB\n#define MEMP_NUM_RAW_PCB                4\n#endif\n\n/**\n * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One\n * per active UDP \"connection\".\n * (requires the LWIP_UDP option)\n */\n#ifndef MEMP_NUM_UDP_PCB\n#define MEMP_NUM_UDP_PCB                4\n#endif\n\n/**\n * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections.\n * (requires the LWIP_TCP option)\n */\n#ifndef MEMP_NUM_TCP_PCB\n#define MEMP_NUM_TCP_PCB                (*(volatile uint32*)0x600011FC)\n#endif\n\n/**\n * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections.\n * (requires the LWIP_TCP option)\n */\n#ifndef MEMP_NUM_TCP_PCB_LISTEN\n#define MEMP_NUM_TCP_PCB_LISTEN         2\n#endif\n\n/**\n * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.\n * (requires the LWIP_TCP option)\n */\n#ifndef MEMP_NUM_TCP_SEG\n#define MEMP_NUM_TCP_SEG                16\n#endif\n\n/**\n * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for\n * reassembly (whole packets, not fragments!)\n */\n#ifndef MEMP_NUM_REASSDATA\n#define MEMP_NUM_REASSDATA              0\n#endif\n\n/**\n * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent\n * (fragments, not whole packets!).\n * This is only used with IP_FRAG_USES_STATIC_BUF==0 and\n * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs\n * where the packet is not yet sent when netif->output returns.\n */\n#ifndef MEMP_NUM_FRAG_PBUF\n#define MEMP_NUM_FRAG_PBUF              0\n#endif\n\n/**\n * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing\n * packets (pbufs) that are waiting for an ARP request (to resolve\n * their destination address) to finish.\n * (requires the ARP_QUEUEING option)\n */\n#ifndef MEMP_NUM_ARP_QUEUE\n#define MEMP_NUM_ARP_QUEUE              10\n#endif\n\n/**\n * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces\n * can be members et the same time (one per netif - allsystems group -, plus one\n * per netif membership).\n * (requires the LWIP_IGMP option)\n */\n#ifndef MEMP_NUM_IGMP_GROUP\n#define MEMP_NUM_IGMP_GROUP             8\n#endif\n\n/**\n * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.\n * (requires NO_SYS==0)\n */\n#ifndef MEMP_NUM_SYS_TIMEOUT\n#define MEMP_NUM_SYS_TIMEOUT            8\n#endif\n\n/**\n * MEMP_NUM_NETBUF: the number of struct netbufs.\n * (only needed if you use the sequential API, like api_lib.c)\n */\n#ifndef MEMP_NUM_NETBUF\n#define MEMP_NUM_NETBUF                 0\n#endif\n\n/**\n * MEMP_NUM_NETCONN: the number of struct netconns.\n * (only needed if you use the sequential API, like api_lib.c)\n */\n#ifndef MEMP_NUM_NETCONN\n#define MEMP_NUM_NETCONN                0\n#endif\n\n/**\n * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used\n * for callback/timeout API communication. \n * (only needed if you use tcpip.c)\n */\n#ifndef MEMP_NUM_TCPIP_MSG_API\n#define MEMP_NUM_TCPIP_MSG_API          4\n#endif\n\n/**\n * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used\n * for incoming packets. \n * (only needed if you use tcpip.c)\n */\n#ifndef MEMP_NUM_TCPIP_MSG_INPKT\n#define MEMP_NUM_TCPIP_MSG_INPKT        4\n#endif\n\n/**\n * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree.\n */\n#ifndef MEMP_NUM_SNMP_NODE\n#define MEMP_NUM_SNMP_NODE              0\n#endif\n\n/**\n * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree.\n * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least!\n */\n#ifndef MEMP_NUM_SNMP_ROOTNODE\n#define MEMP_NUM_SNMP_ROOTNODE          0\n#endif\n\n/**\n * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to\n * be changed normally) - 2 of these are used per request (1 for input,\n * 1 for output)\n */\n#ifndef MEMP_NUM_SNMP_VARBIND\n#define MEMP_NUM_SNMP_VARBIND           0\n#endif\n\n/**\n * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used\n * (does not have to be changed normally) - 3 of these are used per request\n * (1 for the value read and 2 for OIDs - input and output)\n */\n#ifndef MEMP_NUM_SNMP_VALUE\n#define MEMP_NUM_SNMP_VALUE             0\n#endif\n\n/**\n * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls\n * (before freeing the corresponding memory using lwip_freeaddrinfo()).\n */\n#ifndef MEMP_NUM_NETDB\n#define MEMP_NUM_NETDB                  0\n#endif\n\n/**\n * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list\n * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1.\n */\n#ifndef MEMP_NUM_LOCALHOSTLIST\n#define MEMP_NUM_LOCALHOSTLIST          0\n#endif\n\n/**\n * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE\n * interfaces (only used with PPPOE_SUPPORT==1)\n */\n#ifndef MEMP_NUM_PPPOE_INTERFACES\n#define MEMP_NUM_PPPOE_INTERFACES       0\n#endif\n\n/**\n * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. \n */\n#ifndef PBUF_POOL_SIZE\n#define PBUF_POOL_SIZE                  10\n#endif\n\n/*\n   ---------------------------------\n   ---------- ARP options ----------\n   ---------------------------------\n*/\n/**\n * LWIP_ARP==1: Enable ARP functionality.\n */\n#ifndef LWIP_ARP\n#define LWIP_ARP                        1\n#endif\n\n/**\n * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached.\n */\n#ifndef ARP_TABLE_SIZE\n#define ARP_TABLE_SIZE                  10\n#endif\n\n/**\n * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address\n * resolution. By default, only the most recent packet is queued per IP address.\n * This is sufficient for most protocols and mainly reduces TCP connection\n * startup time. Set this to 1 if you know your application sends more than one\n * packet in a row to an IP address that is not in the ARP cache.\n */\n#ifndef ARP_QUEUEING\n#define ARP_QUEUEING                    1\n#endif\n\n/**\n * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be\n * updated with the source MAC and IP addresses supplied in the packet.\n * You may want to disable this if you do not trust LAN peers to have the\n * correct addresses, or as a limited approach to attempt to handle\n * spoofing. If disabled, lwIP will need to make a new ARP request if\n * the peer is not already in the ARP table, adding a little latency.\n * The peer *is* in the ARP table if it requested our address before.\n * Also notice that this slows down input processing of every IP packet!\n */\n#ifndef ETHARP_TRUST_IP_MAC\n#define ETHARP_TRUST_IP_MAC             1\n#endif\n\n/**\n * ETHARP_SUPPORT_VLAN==1: support receiving ethernet packets with VLAN header.\n * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check.\n * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted.\n * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted.\n */\n#ifndef ETHARP_SUPPORT_VLAN\n#define ETHARP_SUPPORT_VLAN             0\n#endif\n\n/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP\n * might be disabled\n */\n#ifndef LWIP_ETHERNET\n#define LWIP_ETHERNET                   (LWIP_ARP || PPPOE_SUPPORT)\n#endif\n\n/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure\n * alignment of payload after that header. Since the header is 14 bytes long,\n * without this padding e.g. addresses in the IP header will not be aligned\n * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms.\n */\n#ifndef ETH_PAD_SIZE\n#define ETH_PAD_SIZE                    0\n#endif\n\n/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table\n * entries (using etharp_add_static_entry/etharp_remove_static_entry).\n */\n#ifndef ETHARP_SUPPORT_STATIC_ENTRIES\n#define ETHARP_SUPPORT_STATIC_ENTRIES   0\n#endif\n\n\n/*\n   --------------------------------\n   ---------- IP options ----------\n   --------------------------------\n*/\n/**\n * IP_FORWARD==1: Enables the ability to forward IP packets across network\n * interfaces. If you are going to run lwIP on a device with only one network\n * interface, define this to 0.\n */\n#ifndef IP_FORWARD\n#define IP_FORWARD                      0\n#endif\n\n/**\n * IP_OPTIONS_ALLOWED: Defines the behavior for IP options.\n *      IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped.\n *      IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed).\n */\n#ifndef IP_OPTIONS_ALLOWED\n#define IP_OPTIONS_ALLOWED              1\n#endif\n\n/**\n * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that\n * this option does not affect outgoing packet sizes, which can be controlled\n * via IP_FRAG.\n */\n#ifndef IP_REASSEMBLY\n#define IP_REASSEMBLY                   0\n#endif\n\n/**\n * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note\n * that this option does not affect incoming packet sizes, which can be\n * controlled via IP_REASSEMBLY.\n */\n#ifndef IP_FRAG\n#define IP_FRAG                         0\n#endif\n\n/**\n * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)\n * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived\n * in this time, the whole packet is discarded.\n */\n#ifndef IP_REASS_MAXAGE\n#define IP_REASS_MAXAGE                 3\n#endif\n\n/**\n * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled.\n * Since the received pbufs are enqueued, be sure to configure\n * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive\n * packets even if the maximum amount of fragments is enqueued for reassembly!\n */\n#ifndef IP_REASS_MAX_PBUFS\n#define IP_REASS_MAX_PBUFS              10\n#endif\n\n/**\n * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP\n * fragmentation. Otherwise pbufs are allocated and reference the original\n * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1,\n * new PBUF_RAM pbufs are used for fragments).\n * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs!\n */\n#ifndef IP_FRAG_USES_STATIC_BUF\n#define IP_FRAG_USES_STATIC_BUF         1\n#endif\n\n/**\n * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer\n * (requires IP_FRAG_USES_STATIC_BUF==1)\n */\n#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU)\n#define IP_FRAG_MAX_MTU                 1500\n#endif\n\n/**\n * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers.\n */\n#ifndef IP_DEFAULT_TTL\n#define IP_DEFAULT_TTL                  255\n#endif\n\n/**\n * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast\n * filter per pcb on udp and raw send operations. To enable broadcast filter\n * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1.\n */\n#ifndef IP_SOF_BROADCAST\n#define IP_SOF_BROADCAST                0\n#endif\n\n/**\n * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast\n * filter on recv operations.\n */\n#ifndef IP_SOF_BROADCAST_RECV\n#define IP_SOF_BROADCAST_RECV           0\n#endif\n\n/*\n   ----------------------------------\n   ---------- ICMP options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_ICMP==1: Enable ICMP module inside the IP stack.\n * Be careful, disable that make your product non-compliant to RFC1122\n */\n#ifndef LWIP_ICMP\n#define LWIP_ICMP                       1\n#endif\n\n/**\n * ICMP_TTL: Default value for Time-To-Live used by ICMP packets.\n */\n#ifndef ICMP_TTL\n#define ICMP_TTL                       (IP_DEFAULT_TTL)\n#endif\n\n/**\n * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only)\n */\n#ifndef LWIP_BROADCAST_PING\n#define LWIP_BROADCAST_PING             0\n#endif\n\n/**\n * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only)\n */\n#ifndef LWIP_MULTICAST_PING\n#define LWIP_MULTICAST_PING             0\n#endif\n\n/*\n   ---------------------------------\n   ---------- RAW options ----------\n   ---------------------------------\n*/\n/**\n * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.\n */\n#ifndef LWIP_RAW\n#define LWIP_RAW                        1\n#endif\n\n/**\n * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.\n */\n#ifndef RAW_TTL\n#define RAW_TTL                        (IP_DEFAULT_TTL)\n#endif\n\n/*\n   ----------------------------------\n   ---------- DHCP options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_DHCP==1: Enable DHCP module.\n */\n#ifndef LWIP_DHCP\n#define LWIP_DHCP                       1\n#endif\n\n/**\n * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address.\n */\n#ifndef DHCP_DOES_ARP_CHECK\n#define DHCP_DOES_ARP_CHECK             ((LWIP_DHCP) && (LWIP_ARP))\n#endif\n\n/**\n * DHCP_MAXRTX: Maximum number of retries of current request.\n */\n#ifndef DHCP_MAXRTX\n#define DHCP_MAXRTX                 (*(volatile uint32*)0x600011E0)\n#endif\n\n/*\n   ------------------------------------\n   ---------- AUTOIP options ----------\n   ------------------------------------\n*/\n/**\n * LWIP_AUTOIP==1: Enable AUTOIP module.\n */\n#ifndef LWIP_AUTOIP\n#define LWIP_AUTOIP                     0\n#endif\n\n/**\n * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on\n * the same interface at the same time.\n */\n#ifndef LWIP_DHCP_AUTOIP_COOP\n#define LWIP_DHCP_AUTOIP_COOP           0\n#endif\n\n/**\n * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes\n * that should be sent before falling back on AUTOIP. This can be set\n * as low as 1 to get an AutoIP address very quickly, but you should\n * be prepared to handle a changing IP address when DHCP overrides\n * AutoIP.\n */\n#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES\n#define LWIP_DHCP_AUTOIP_COOP_TRIES     9\n#endif\n\n/*\n   ----------------------------------\n   ---------- SNMP options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP\n * transport.\n */\n#ifndef LWIP_SNMP\n#define LWIP_SNMP                       0\n#endif\n\n/**\n * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will\n * allow. At least one request buffer is required. \n */\n#ifndef SNMP_CONCURRENT_REQUESTS\n#define SNMP_CONCURRENT_REQUESTS        0\n#endif\n\n/**\n * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap\n * destination is required\n */\n#ifndef SNMP_TRAP_DESTINATIONS\n#define SNMP_TRAP_DESTINATIONS          0\n#endif\n\n/**\n * SNMP_PRIVATE_MIB: \n */\n#ifndef SNMP_PRIVATE_MIB\n#define SNMP_PRIVATE_MIB                0\n#endif\n\n/**\n * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not\n * a safe action and disabled when SNMP_SAFE_REQUESTS = 1).\n * Unsafe requests are disabled by default!\n */\n#ifndef SNMP_SAFE_REQUESTS\n#define SNMP_SAFE_REQUESTS              0\n#endif\n\n/**\n * The maximum length of strings used. This affects the size of\n * MEMP_SNMP_VALUE elements.\n */\n#ifndef SNMP_MAX_OCTET_STRING_LEN\n#define SNMP_MAX_OCTET_STRING_LEN       127\n#endif\n\n/**\n * The maximum depth of the SNMP tree.\n * With private MIBs enabled, this depends on your MIB!\n * This affects the size of MEMP_SNMP_VALUE elements.\n */\n#ifndef SNMP_MAX_TREE_DEPTH\n#define SNMP_MAX_TREE_DEPTH             15\n#endif\n\n/**\n * The size of the MEMP_SNMP_VALUE elements, normally calculated from\n * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH.\n */\n#ifndef SNMP_MAX_VALUE_SIZE\n#define SNMP_MAX_VALUE_SIZE             LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH))\n#endif\n\n/*\n   ----------------------------------\n   ---------- IGMP options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_IGMP==1: Turn on IGMP module. \n */\n#ifndef LWIP_IGMP\n#define LWIP_IGMP                       1\n#endif\n/*\n   ----------------------------------\n   ---------- MDNS options ----------\n   ----------------------------------\n*/\n/**\n * LWIP_MDNS==1: Turn on MDNS module.\n */\n#ifndef LWIP_MDNS\n#define LWIP_MDNS                      1\n#endif\n/*\n/*\n   ----------------------------------\n   ---------- DNS options -----------\n   ----------------------------------\n*/\n/**\n * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS\n * transport.\n */\n#ifndef LWIP_DNS\n#define LWIP_DNS                        1\n#endif\n\n/** DNS maximum number of entries to maintain locally. */\n#ifndef DNS_TABLE_SIZE\n#define DNS_TABLE_SIZE                  4\n#endif\n\n/** DNS maximum host name length supported in the name table. */\n#ifndef DNS_MAX_NAME_LENGTH\n#define DNS_MAX_NAME_LENGTH             256\n#endif\n\n/** The maximum of DNS servers */\n#ifndef DNS_MAX_SERVERS\n#define DNS_MAX_SERVERS                 2\n#endif\n\n/** DNS do a name checking between the query and the response. */\n#ifndef DNS_DOES_NAME_CHECK\n#define DNS_DOES_NAME_CHECK             1\n#endif\n\n/** DNS message max. size. Default value is RFC compliant. */\n#ifndef DNS_MSG_SIZE\n#define DNS_MSG_SIZE                    512\n#endif\n\n/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled,\n *  you have to define\n *    #define DNS_LOCAL_HOSTLIST_INIT {{\"host1\", 0x123}, {\"host2\", 0x234}}\n *  (an array of structs name/address, where address is an u32_t in network\n *  byte order).\n *\n *  Instead, you can also use an external function:\n *  #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name)\n *  that returns the IP address or INADDR_NONE if not found.\n */\n#ifndef DNS_LOCAL_HOSTLIST\n#define DNS_LOCAL_HOSTLIST              0\n#endif /* DNS_LOCAL_HOSTLIST */\n\n/** If this is turned on, the local host-list can be dynamically changed\n *  at runtime. */\n#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC\n#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC   0\n#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n\n/*\n   ---------------------------------\n   ---------- UDP options ----------\n   ---------------------------------\n*/\n/**\n * LWIP_UDP==1: Turn on UDP.\n */\n#ifndef LWIP_UDP\n#define LWIP_UDP                        1\n#endif\n\n/**\n * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP)\n */\n#ifndef LWIP_UDPLITE\n#define LWIP_UDPLITE                    0\n#endif\n\n/**\n * UDP_TTL: Default Time-To-Live value.\n */\n#ifndef UDP_TTL\n#define UDP_TTL                         (IP_DEFAULT_TTL)\n#endif\n\n/**\n * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf.\n */\n#ifndef LWIP_NETBUF_RECVINFO\n#define LWIP_NETBUF_RECVINFO            0\n#endif\n\n/*\n   ---------------------------------\n   ---------- TCP options ----------\n   ---------------------------------\n*/\n/**\n * LWIP_TCP==1: Turn on TCP.\n */\n#ifndef LWIP_TCP\n#define LWIP_TCP                        1\n#endif\n\n/**\n * TCP_TTL: Default Time-To-Live value.\n */\n#ifndef TCP_TTL\n#define TCP_TTL                         (IP_DEFAULT_TTL)\n#endif\n\n/**\n * TCP_WND: The size of a TCP window.  This must be at least \n * (2 * TCP_MSS) for things to work well\n */\n#ifndef TCP_WND\n#define TCP_WND                         (*(volatile uint32*)0x600011F0)\n#endif \n\n/**\n * TCP_MAXRTX: Maximum number of retransmissions of data segments.\n */\n#ifndef TCP_MAXRTX\n#define TCP_MAXRTX                      (*(volatile uint32*)0x600011E8)\n#endif\n\n/**\n * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.\n */\n#ifndef TCP_SYNMAXRTX\n#define TCP_SYNMAXRTX                   (*(volatile uint32*)0x600011E4)\n#endif\n\n/**\n * TCP_MAXRTO: Maximum retransmission timeout of data segments.\n */\n#ifndef TCP_MAXRTO\n#define TCP_MAXRTO                      10\n#endif\n\n/**\n * TCP_MINRTO: Minimum retransmission timeout of data segments.\n */\n#ifndef TCP_MINRTO\n#define TCP_MINRTO                      2\n#endif\n\n/**\n * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order.\n * Define to 0 if your device is low on memory.\n */\n#ifndef TCP_QUEUE_OOSEQ\n#define TCP_QUEUE_OOSEQ                 1\n#endif\n\n#if 1\n/**\n * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default,\n * you might want to increase this.)\n * For the receive side, this MSS is advertised to the remote side\n * when opening a connection. For the transmit size, this MSS sets\n * an upper limit on the MSS advertised by the remote host.\n */\n#ifndef TCP_MSS\n#define TCP_MSS                         1460\n#endif\n#endif\n\n/**\n * TCP_CALCULATE_EFF_SEND_MSS: \"The maximum size of a segment that TCP really\n * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which\n * reflects the available reassembly buffer size at the remote host) and the\n * largest size permitted by the IP layer\" (RFC 1122)\n * Setting this to 1 enables code that checks TCP_MSS against the MTU of the\n * netif used for a connection and limits the MSS if it would be too big otherwise.\n */\n#ifndef TCP_CALCULATE_EFF_SEND_MSS\n#define TCP_CALCULATE_EFF_SEND_MSS      1\n#endif\n\n\n/**\n * TCP_SND_BUF: TCP sender buffer space (bytes). \n */\n#ifndef TCP_SND_BUF\n#define TCP_SND_BUF                     2 * TCP_MSS\n#endif\n\n/**\n * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least\n * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.\n */\n#ifndef TCP_SND_QUEUELEN\n#define TCP_SND_QUEUELEN                ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))\n#endif\n\n/**\n * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than\n * TCP_SND_BUF. It is the amount of space which must be available in the\n * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT).\n */\n#ifndef TCP_SNDLOWAT\n#define TCP_SNDLOWAT                    ((TCP_SND_BUF)/2)\n#endif\n\n/**\n * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater\n * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below\n * this number, select returns writable (combined with TCP_SNDLOWAT).\n */\n#ifndef TCP_SNDQUEUELOWAT\n#define TCP_SNDQUEUELOWAT               LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5)\n#endif\n\n/**\n * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.\n */\n#ifndef TCP_LISTEN_BACKLOG\n#define TCP_LISTEN_BACKLOG              0\n#endif\n\n/**\n * The maximum allowed backlog for TCP listen netconns.\n * This backlog is used unless another is explicitly specified.\n * 0xff is the maximum (u8_t).\n */\n#ifndef TCP_DEFAULT_LISTEN_BACKLOG\n#define TCP_DEFAULT_LISTEN_BACKLOG      0xff\n#endif\n\n/**\n * TCP_OVERSIZE: The maximum number of bytes that tcp_write may\n * allocate ahead of time in an attempt to create shorter pbuf chains\n * for transmission. The meaningful range is 0 to TCP_MSS. Some\n * suggested values are:\n *\n * 0:         Disable oversized allocation. Each tcp_write() allocates a new\n              pbuf (old behaviour).\n * 1:         Allocate size-aligned pbufs with minimal excess. Use this if your\n *            scatter-gather DMA requires aligned fragments.\n * 128:       Limit the pbuf/memory overhead to 20%.\n * TCP_MSS:   Try to create unfragmented TCP packets.\n * TCP_MSS/4: Try to create 4 fragments or less per TCP packet.\n */\n#ifndef TCP_OVERSIZE\n#define TCP_OVERSIZE                    TCP_MSS\n#endif\n\n/**\n * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option.\n */\n#ifndef LWIP_TCP_TIMESTAMPS\n#define LWIP_TCP_TIMESTAMPS             0\n#endif\n\n/**\n * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an\n * explicit window update\n */\n#ifndef TCP_WND_UPDATE_THRESHOLD\n#define TCP_WND_UPDATE_THRESHOLD   (TCP_WND / 4)\n#endif\n\n/**\n * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1.\n *     LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all\n *         events (accept, sent, etc) that happen in the system.\n *     LWIP_CALLBACK_API==1: The PCB callback function is called directly\n *         for the event.\n */\n#ifndef LWIP_EVENT_API\n#define LWIP_EVENT_API                  0\n#define LWIP_CALLBACK_API               1\n#else \n#define LWIP_EVENT_API                  1\n#define LWIP_CALLBACK_API               0\n#endif\n\n\n/*\n   ----------------------------------\n   ---------- Pbuf options ----------\n   ----------------------------------\n*/\n/**\n * PBUF_LINK_HLEN: the number of bytes that should be allocated for a\n * link level header. The default is 14, the standard value for\n * Ethernet.\n */\n#ifndef PBUF_LINK_HLEN\n#define PBUF_LINK_HLEN                  (14 + ETH_PAD_SIZE)\n#endif\n\n/**\n * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is\n * designed to accomodate single full size TCP frame in one pbuf, including\n * TCP_MSS, IP header, and link header.\n */\n#ifndef PBUF_POOL_BUFSIZE\n#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)\n#endif\n\n/*\n   ------------------------------------------------\n   ---------- Network Interfaces options ----------\n   ------------------------------------------------\n*/\n/**\n * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname\n * field.\n */\n#ifndef LWIP_NETIF_HOSTNAME\n#define LWIP_NETIF_HOSTNAME             1\n#endif\n\n/**\n * LWIP_NETIF_API==1: Support netif api (in netifapi.c)\n */\n#ifndef LWIP_NETIF_API\n#define LWIP_NETIF_API                  0\n#endif\n\n/**\n * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface\n * changes its up/down status (i.e., due to DHCP IP acquistion)\n */\n#ifndef LWIP_NETIF_STATUS_CALLBACK\n#define LWIP_NETIF_STATUS_CALLBACK      0\n#endif\n\n/**\n * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface\n * whenever the link changes (i.e., link down)\n */\n#ifndef LWIP_NETIF_LINK_CALLBACK\n#define LWIP_NETIF_LINK_CALLBACK        0\n#endif\n\n/**\n * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table\n * indices) in struct netif. TCP and UDP can make use of this to prevent\n * scanning the ARP table for every sent packet. While this is faster for big\n * ARP tables or many concurrent connections, it might be counterproductive\n * if you have a tiny ARP table or if there never are concurrent connections.\n */\n#ifndef LWIP_NETIF_HWADDRHINT\n#define LWIP_NETIF_HWADDRHINT           0\n#endif\n\n/**\n * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP\n * address equal to the netif IP address, looping them back up the stack.\n */\n#ifndef LWIP_NETIF_LOOPBACK\n#define LWIP_NETIF_LOOPBACK             0\n#endif\n\n/**\n * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback\n * sending for each netif (0 = disabled)\n */\n#ifndef LWIP_LOOPBACK_MAX_PBUFS\n#define LWIP_LOOPBACK_MAX_PBUFS         0\n#endif\n\n/**\n * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in\n * the system, as netifs must change how they behave depending on this setting\n * for the LWIP_NETIF_LOOPBACK option to work.\n * Setting this is needed to avoid reentering non-reentrant functions like\n * tcp_input().\n *    LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a\n *       multithreaded environment like tcpip.c. In this case, netif->input()\n *       is called directly.\n *    LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.\n *       The packets are put on a list and netif_poll() must be called in\n *       the main application loop.\n */\n#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING\n#define LWIP_NETIF_LOOPBACK_MULTITHREADING    (!NO_SYS)\n#endif\n\n/**\n * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data\n * to be sent into one single pbuf. This is for compatibility with DMA-enabled\n * MACs that do not support scatter-gather.\n * Beware that this might involve CPU-memcpy before transmitting that would not\n * be needed without this flag! Use this only if you need to!\n *\n * @todo: TCP and IP-frag do not work with this, yet:\n */\n#ifndef LWIP_NETIF_TX_SINGLE_PBUF\n#define LWIP_NETIF_TX_SINGLE_PBUF             1\n#endif /* LWIP_NETIF_TX_SINGLE_PBUF */\n\n/*\n   ------------------------------------\n   ---------- LOOPIF options ----------\n   ------------------------------------\n*/\n/**\n * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c\n */\n#ifndef LWIP_HAVE_LOOPIF\n#define LWIP_HAVE_LOOPIF                0\n#endif\n\n/*\n   ------------------------------------\n   ---------- SLIPIF options ----------\n   ------------------------------------\n*/\n/**\n * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c\n */\n#ifndef LWIP_HAVE_SLIPIF\n#define LWIP_HAVE_SLIPIF                0\n#endif\n\n/*\n   ------------------------------------\n   ---------- Thread options ----------\n   ------------------------------------\n*/\n/**\n * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread.\n */\n#ifndef TCPIP_THREAD_NAME\n#define TCPIP_THREAD_NAME              \"tcpip_thread\"\n#endif\n\n/**\n * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread.\n * The stack size value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef TCPIP_THREAD_STACKSIZE\n#define TCPIP_THREAD_STACKSIZE          0\n#endif\n\n/**\n * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread.\n * The priority value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef TCPIP_THREAD_PRIO\n#define TCPIP_THREAD_PRIO               1\n#endif\n\n/**\n * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages\n * The queue size value itself is platform-dependent, but is passed to\n * sys_mbox_new() when tcpip_init is called.\n */\n#ifndef TCPIP_MBOX_SIZE\n#define TCPIP_MBOX_SIZE                 0\n#endif\n\n/**\n * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread.\n */\n#ifndef SLIPIF_THREAD_NAME\n#define SLIPIF_THREAD_NAME             \"slipif_loop\"\n#endif\n\n/**\n * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread.\n * The stack size value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef SLIPIF_THREAD_STACKSIZE\n#define SLIPIF_THREAD_STACKSIZE         0\n#endif\n\n/**\n * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread.\n * The priority value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef SLIPIF_THREAD_PRIO\n#define SLIPIF_THREAD_PRIO              1\n#endif\n\n/**\n * PPP_THREAD_NAME: The name assigned to the pppInputThread.\n */\n#ifndef PPP_THREAD_NAME\n#define PPP_THREAD_NAME                \"pppInputThread\"\n#endif\n\n/**\n * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread.\n * The stack size value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef PPP_THREAD_STACKSIZE\n#define PPP_THREAD_STACKSIZE            0\n#endif\n\n/**\n * PPP_THREAD_PRIO: The priority assigned to the pppInputThread.\n * The priority value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef PPP_THREAD_PRIO\n#define PPP_THREAD_PRIO                 1\n#endif\n\n/**\n * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread.\n */\n#ifndef DEFAULT_THREAD_NAME\n#define DEFAULT_THREAD_NAME            \"lwIP\"\n#endif\n\n/**\n * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread.\n * The stack size value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef DEFAULT_THREAD_STACKSIZE\n#define DEFAULT_THREAD_STACKSIZE        0\n#endif\n\n/**\n * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread.\n * The priority value itself is platform-dependent, but is passed to\n * sys_thread_new() when the thread is created.\n */\n#ifndef DEFAULT_THREAD_PRIO\n#define DEFAULT_THREAD_PRIO             1\n#endif\n\n/**\n * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\n * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed\n * to sys_mbox_new() when the recvmbox is created.\n */\n#ifndef DEFAULT_RAW_RECVMBOX_SIZE\n#define DEFAULT_RAW_RECVMBOX_SIZE       0\n#endif\n\n/**\n * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\n * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed\n * to sys_mbox_new() when the recvmbox is created.\n */\n#ifndef DEFAULT_UDP_RECVMBOX_SIZE\n#define DEFAULT_UDP_RECVMBOX_SIZE       0\n#endif\n\n/**\n * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\n * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed\n * to sys_mbox_new() when the recvmbox is created.\n */\n#ifndef DEFAULT_TCP_RECVMBOX_SIZE\n#define DEFAULT_TCP_RECVMBOX_SIZE       0\n#endif\n\n/**\n * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections.\n * The queue size value itself is platform-dependent, but is passed to\n * sys_mbox_new() when the acceptmbox is created.\n */\n#ifndef DEFAULT_ACCEPTMBOX_SIZE\n#define DEFAULT_ACCEPTMBOX_SIZE         0\n#endif\n\n/*\n   ----------------------------------------------\n   ---------- Sequential layer options ----------\n   ----------------------------------------------\n*/\n/**\n * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!)\n * Don't use it if you're not an active lwIP project member\n */\n#ifndef LWIP_TCPIP_CORE_LOCKING\n#define LWIP_TCPIP_CORE_LOCKING         0\n#endif\n\n/**\n * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!)\n * Don't use it if you're not an active lwIP project member\n */\n#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT\n#define LWIP_TCPIP_CORE_LOCKING_INPUT   0\n#endif\n\n/**\n * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)\n */\n#ifndef LWIP_NETCONN\n#define LWIP_NETCONN                    0\n#endif\n\n/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create\n * timers running in tcpip_thread from another thread.\n */\n#ifndef LWIP_TCPIP_TIMEOUT\n#define LWIP_TCPIP_TIMEOUT              1\n#endif\n\n/*\n   ------------------------------------\n   ---------- Socket options ----------\n   ------------------------------------\n*/\n/**\n * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)\n */\n#ifndef LWIP_SOCKET\n#define LWIP_SOCKET                     0\n#endif\n\n/**\n * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names.\n * (only used if you use sockets.c)\n */\n#ifndef LWIP_COMPAT_SOCKETS\n#define LWIP_COMPAT_SOCKETS             0\n#endif\n\n/**\n * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.\n * Disable this option if you use a POSIX operating system that uses the same\n * names (read, write & close). (only used if you use sockets.c)\n */\n#ifndef LWIP_POSIX_SOCKETS_IO_NAMES\n#define LWIP_POSIX_SOCKETS_IO_NAMES     0\n#endif\n\n/**\n * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT\n * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set\n * in seconds. (does not require sockets.c, and will affect tcp.c)\n */\n#ifndef LWIP_TCP_KEEPALIVE\n#define LWIP_TCP_KEEPALIVE              1\n#endif\n\n/**\n * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing.\n */\n#ifndef LWIP_SO_RCVTIMEO\n#define LWIP_SO_RCVTIMEO                0\n#endif\n\n/**\n * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.\n */\n#ifndef LWIP_SO_RCVBUF\n#define LWIP_SO_RCVBUF                  0\n#endif\n\n/**\n * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize.\n */\n#ifndef RECV_BUFSIZE_DEFAULT\n#define RECV_BUFSIZE_DEFAULT            INT_MAX\n#endif\n\n/**\n * SO_REUSE==1: Enable SO_REUSEADDR option.\n */\n#ifndef SO_REUSE\n#define SO_REUSE                        0\n#endif\n\n/**\n * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets\n * to all local matches if SO_REUSEADDR is turned on.\n * WARNING: Adds a memcpy for every packet if passing to more than one pcb!\n */\n#ifndef SO_REUSE_RXTOALL\n#define SO_REUSE_RXTOALL                0\n#endif\n\n/*\n   ----------------------------------------\n   ---------- Statistics options ----------\n   ----------------------------------------\n*/\n/**\n * LWIP_STATS==1: Enable statistics collection in lwip_stats.\n */\n#ifndef LWIP_STATS\n#define LWIP_STATS                      0\n#endif\n\n#if LWIP_STATS\n\n/**\n * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions.\n */\n#ifndef LWIP_STATS_DISPLAY\n#define LWIP_STATS_DISPLAY              0\n#endif\n\n/**\n * LINK_STATS==1: Enable link stats.\n */\n#ifndef LINK_STATS\n#define LINK_STATS                      1\n#endif\n\n/**\n * ETHARP_STATS==1: Enable etharp stats.\n */\n#ifndef ETHARP_STATS\n#define ETHARP_STATS                    (LWIP_ARP)\n#endif\n\n/**\n * IP_STATS==1: Enable IP stats.\n */\n#ifndef IP_STATS\n#define IP_STATS                        1\n#endif\n\n/**\n * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is\n * on if using either frag or reass.\n */\n#ifndef IPFRAG_STATS\n#define IPFRAG_STATS                    (IP_REASSEMBLY || IP_FRAG)\n#endif\n\n/**\n * ICMP_STATS==1: Enable ICMP stats.\n */\n#ifndef ICMP_STATS\n#define ICMP_STATS                      1\n#endif\n\n/**\n * IGMP_STATS==1: Enable IGMP stats.\n */\n#ifndef IGMP_STATS\n#define IGMP_STATS                      (LWIP_IGMP)\n#endif\n\n/**\n * UDP_STATS==1: Enable UDP stats. Default is on if\n * UDP enabled, otherwise off.\n */\n#ifndef UDP_STATS\n#define UDP_STATS                       (LWIP_UDP)\n#endif\n\n/**\n * TCP_STATS==1: Enable TCP stats. Default is on if TCP\n * enabled, otherwise off.\n */\n#ifndef TCP_STATS\n#define TCP_STATS                       (LWIP_TCP)\n#endif\n\n/**\n * MEM_STATS==1: Enable mem.c stats.\n */\n#ifndef MEM_STATS\n#define MEM_STATS                       ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0))\n#endif\n\n/**\n * MEMP_STATS==1: Enable memp.c pool stats.\n */\n#ifndef MEMP_STATS\n#define MEMP_STATS                      (MEMP_MEM_MALLOC == 0)\n#endif\n\n/**\n * SYS_STATS==1: Enable system stats (sem and mbox counts, etc).\n */\n#ifndef SYS_STATS\n#define SYS_STATS                       (NO_SYS == 0)\n#endif\n\n#else\n#define ETHARP_STATS                    0\n#define LINK_STATS                      0\n#define IP_STATS                        0\n#define IPFRAG_STATS                    0\n#define ICMP_STATS                      0\n#define IGMP_STATS                      0\n#define UDP_STATS                       0\n#define TCP_STATS                       0\n#define MEM_STATS                       0\n#define MEMP_STATS                      0\n#define SYS_STATS                       0\n#define LWIP_STATS_DISPLAY              0\n\n#endif /* LWIP_STATS */\n\n/*\n   ---------------------------------\n   ---------- PPP options ----------\n   ---------------------------------\n*/\n/**\n * PPP_SUPPORT==1: Enable PPP.\n */\n#ifndef PPP_SUPPORT\n#define PPP_SUPPORT                     0\n#endif\n\n/**\n * PPPOE_SUPPORT==1: Enable PPP Over Ethernet\n */\n#ifndef PPPOE_SUPPORT\n#define PPPOE_SUPPORT                   0\n#endif\n\n/**\n * PPPOS_SUPPORT==1: Enable PPP Over Serial\n */\n#ifndef PPPOS_SUPPORT\n#define PPPOS_SUPPORT                   PPP_SUPPORT\n#endif\n\n#if PPP_SUPPORT\n\n/**\n * NUM_PPP: Max PPP sessions.\n */\n#ifndef NUM_PPP\n#define NUM_PPP                         1\n#endif\n\n/**\n * PAP_SUPPORT==1: Support PAP.\n */\n#ifndef PAP_SUPPORT\n#define PAP_SUPPORT                     0\n#endif\n\n/**\n * CHAP_SUPPORT==1: Support CHAP.\n */\n#ifndef CHAP_SUPPORT\n#define CHAP_SUPPORT                    0\n#endif\n\n/**\n * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET!\n */\n#ifndef MSCHAP_SUPPORT\n#define MSCHAP_SUPPORT                  0\n#endif\n\n/**\n * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET!\n */\n#ifndef CBCP_SUPPORT\n#define CBCP_SUPPORT                    0\n#endif\n\n/**\n * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET!\n */\n#ifndef CCP_SUPPORT\n#define CCP_SUPPORT                     0\n#endif\n\n/**\n * VJ_SUPPORT==1: Support VJ header compression.\n */\n#ifndef VJ_SUPPORT\n#define VJ_SUPPORT                      0\n#endif\n\n/**\n * MD5_SUPPORT==1: Support MD5 (see also CHAP).\n */\n#ifndef MD5_SUPPORT\n#define MD5_SUPPORT                     0\n#endif\n\n/*\n * Timeouts\n */\n#ifndef FSM_DEFTIMEOUT\n#define FSM_DEFTIMEOUT                  6       /* Timeout time in seconds */\n#endif\n\n#ifndef FSM_DEFMAXTERMREQS\n#define FSM_DEFMAXTERMREQS              2       /* Maximum Terminate-Request transmissions */\n#endif\n\n#ifndef FSM_DEFMAXCONFREQS\n#define FSM_DEFMAXCONFREQS              10      /* Maximum Configure-Request transmissions */\n#endif\n\n#ifndef FSM_DEFMAXNAKLOOPS\n#define FSM_DEFMAXNAKLOOPS              5       /* Maximum number of nak loops */\n#endif\n\n#ifndef UPAP_DEFTIMEOUT\n#define UPAP_DEFTIMEOUT                 6       /* Timeout (seconds) for retransmitting req */\n#endif\n\n#ifndef UPAP_DEFREQTIME\n#define UPAP_DEFREQTIME                 30      /* Time to wait for auth-req from peer */\n#endif\n\n#ifndef CHAP_DEFTIMEOUT\n#define CHAP_DEFTIMEOUT                 6       /* Timeout time in seconds */\n#endif\n\n#ifndef CHAP_DEFTRANSMITS\n#define CHAP_DEFTRANSMITS               10      /* max # times to send challenge */\n#endif\n\n/* Interval in seconds between keepalive echo requests, 0 to disable. */\n#ifndef LCP_ECHOINTERVAL\n#define LCP_ECHOINTERVAL                0\n#endif\n\n/* Number of unanswered echo requests before failure. */\n#ifndef LCP_MAXECHOFAILS\n#define LCP_MAXECHOFAILS                3\n#endif\n\n/* Max Xmit idle time (in jiffies) before resend flag char. */\n#ifndef PPP_MAXIDLEFLAG\n#define PPP_MAXIDLEFLAG                 100\n#endif\n\n/*\n * Packet sizes\n *\n * Note - lcp shouldn't be allowed to negotiate stuff outside these\n *    limits.  See lcp.h in the pppd directory.\n * (XXX - these constants should simply be shared by lcp.c instead\n *    of living in lcp.h)\n */\n#define PPP_MTU                         1500     /* Default MTU (size of Info field) */\n#ifndef PPP_MAXMTU\n/* #define PPP_MAXMTU  65535 - (PPP_HDRLEN + PPP_FCSLEN) */\n#define PPP_MAXMTU                      1500 /* Largest MTU we allow */\n#endif\n#define PPP_MINMTU                      64\n#define PPP_MRU                         1500     /* default MRU = max length of info field */\n#define PPP_MAXMRU                      1500     /* Largest MRU we allow */\n#ifndef PPP_DEFMRU\n#define PPP_DEFMRU                      296             /* Try for this */\n#endif\n#define PPP_MINMRU                      128             /* No MRUs below this */\n\n#ifndef MAXNAMELEN\n#define MAXNAMELEN                      256     /* max length of hostname or name for auth */\n#endif\n#ifndef MAXSECRETLEN\n#define MAXSECRETLEN                    256     /* max length of password or secret */\n#endif\n\n#endif /* PPP_SUPPORT */\n\n/*\n   --------------------------------------\n   ---------- Checksum options ----------\n   --------------------------------------\n*/\n/**\n * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.\n */\n#ifndef CHECKSUM_GEN_IP\n#define CHECKSUM_GEN_IP                 1\n#endif\n \n/**\n * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.\n */\n#ifndef CHECKSUM_GEN_UDP\n#define CHECKSUM_GEN_UDP                1\n#endif\n \n/**\n * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.\n */\n#ifndef CHECKSUM_GEN_TCP\n#define CHECKSUM_GEN_TCP                1\n#endif\n \n/**\n * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.\n */\n#ifndef CHECKSUM_CHECK_IP\n#define CHECKSUM_CHECK_IP               1\n#endif\n \n/**\n * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.\n */\n#ifndef CHECKSUM_CHECK_UDP\n#define CHECKSUM_CHECK_UDP              1\n#endif\n\n/**\n * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.\n */\n#ifndef CHECKSUM_CHECK_TCP\n#define CHECKSUM_CHECK_TCP              1\n#endif\n\n/**\n * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from\n * application buffers to pbufs.\n */\n#ifndef LWIP_CHECKSUM_ON_COPY\n#define LWIP_CHECKSUM_ON_COPY           0\n#endif\n\n/*\n   ---------------------------------------\n   ---------- Debugging options ----------\n   ---------------------------------------\n*/\n/**\n * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is\n * compared against this value. If it is smaller, then debugging\n * messages are written.\n */\n#ifndef LWIP_DBG_MIN_LEVEL\n#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL\n#endif\n\n/**\n * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable\n * debug messages of certain types.\n */\n#ifndef LWIP_DBG_TYPES_ON\n#define LWIP_DBG_TYPES_ON               LWIP_DBG_OFF\n#endif\n\n/**\n * ETHARP_DEBUG: Enable debugging in etharp.c.\n */\n#ifndef ETHARP_DEBUG\n#define ETHARP_DEBUG                    LWIP_DBG_OFF\n#endif\n\n/**\n * NETIF_DEBUG: Enable debugging in netif.c.\n */\n#ifndef NETIF_DEBUG\n#define NETIF_DEBUG                     LWIP_DBG_OFF\n#endif\n\n/**\n * PBUF_DEBUG: Enable debugging in pbuf.c.\n */\n#ifndef PBUF_DEBUG\n#define PBUF_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * API_LIB_DEBUG: Enable debugging in api_lib.c.\n */\n#ifndef API_LIB_DEBUG\n#define API_LIB_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * API_MSG_DEBUG: Enable debugging in api_msg.c.\n */\n#ifndef API_MSG_DEBUG\n#define API_MSG_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * SOCKETS_DEBUG: Enable debugging in sockets.c.\n */\n#ifndef SOCKETS_DEBUG\n#define SOCKETS_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * ICMP_DEBUG: Enable debugging in icmp.c.\n */\n#ifndef ICMP_DEBUG\n#define ICMP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * IGMP_DEBUG: Enable debugging in igmp.c.\n */\n#ifndef IGMP_DEBUG\n#define IGMP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * INET_DEBUG: Enable debugging in inet.c.\n */\n#ifndef INET_DEBUG\n#define INET_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * IP_DEBUG: Enable debugging for IP.\n */\n#ifndef IP_DEBUG\n#define IP_DEBUG                        LWIP_DBG_OFF\n#endif\n\n/**\n * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass.\n */\n#ifndef IP_REASS_DEBUG\n#define IP_REASS_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * RAW_DEBUG: Enable debugging in raw.c.\n */\n#ifndef RAW_DEBUG\n#define RAW_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * MEM_DEBUG: Enable debugging in mem.c.\n */\n#ifndef MEM_DEBUG\n#define MEM_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * MEMP_DEBUG: Enable debugging in memp.c.\n */\n#ifndef MEMP_DEBUG\n#define MEMP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * SYS_DEBUG: Enable debugging in sys.c.\n */\n#ifndef SYS_DEBUG\n#define SYS_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * TIMERS_DEBUG: Enable debugging in timers.c.\n */\n#ifndef TIMERS_DEBUG\n#define TIMERS_DEBUG                    LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_DEBUG: Enable debugging for TCP.\n */\n#ifndef TCP_DEBUG\n#define TCP_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.\n */\n#ifndef TCP_INPUT_DEBUG\n#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit.\n */\n#ifndef TCP_FR_DEBUG\n#define TCP_FR_DEBUG                    LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit\n * timeout.\n */\n#ifndef TCP_RTO_DEBUG\n#define TCP_RTO_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_CWND_DEBUG: Enable debugging for TCP congestion window.\n */\n#ifndef TCP_CWND_DEBUG\n#define TCP_CWND_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating.\n */\n#ifndef TCP_WND_DEBUG\n#define TCP_WND_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.\n */\n#ifndef TCP_OUTPUT_DEBUG\n#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_RST_DEBUG: Enable debugging for TCP with the RST message.\n */\n#ifndef TCP_RST_DEBUG\n#define TCP_RST_DEBUG                   LWIP_DBG_OFF\n#endif\n\n/**\n * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths.\n */\n#ifndef TCP_QLEN_DEBUG\n#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * UDP_DEBUG: Enable debugging in UDP.\n */\n#ifndef UDP_DEBUG\n#define UDP_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * TCPIP_DEBUG: Enable debugging in tcpip.c.\n */\n#ifndef TCPIP_DEBUG\n#define TCPIP_DEBUG                     LWIP_DBG_OFF\n#endif\n\n/**\n * PPP_DEBUG: Enable debugging for PPP.\n */\n#ifndef PPP_DEBUG\n#define PPP_DEBUG                       LWIP_DBG_OFF\n#endif\n\n/**\n * SLIP_DEBUG: Enable debugging in slipif.c.\n */\n#ifndef SLIP_DEBUG\n#define SLIP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * DHCP_DEBUG: Enable debugging in dhcp.c.\n */\n#ifndef DHCP_DEBUG\n#define DHCP_DEBUG                      LWIP_DBG_OFF\n#endif\n\n/**\n * AUTOIP_DEBUG: Enable debugging in autoip.c.\n */\n#ifndef AUTOIP_DEBUG\n#define AUTOIP_DEBUG                    LWIP_DBG_OFF\n#endif\n\n/**\n * SNMP_MSG_DEBUG: Enable debugging for SNMP messages.\n */\n#ifndef SNMP_MSG_DEBUG\n#define SNMP_MSG_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs.\n */\n#ifndef SNMP_MIB_DEBUG\n#define SNMP_MIB_DEBUG                  LWIP_DBG_OFF\n#endif\n\n/**\n * DNS_DEBUG: Enable debugging for DNS.\n */\n#ifndef DNS_DEBUG\n#define DNS_DEBUG                       LWIP_DBG_OFF\n#endif\n\n#endif /* __LWIP_OPT_H__ */\n"
  },
  {
    "path": "app/include/mem_manager.h",
    "content": "#ifndef __MEM_MANAGER_H__\n#define __MEM_MANAGER_H__\n\n#include \"c_types.h\"\n\n/*------------------------------------------------*/\n\n#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\n#ifndef IOT_SIP_MODE\n//#define configTOTAL_HEAP_SIZE\t\t\t( ( size_t ) ( 0x3fffc000 - (uint32)&_heap_start ) )//fix 16000 to 24000 on 14.2.26\n#else\n#define configTOTAL_HEAP_SIZE\t\t\t( ( size_t ) ( 8000 ) )\n#endif\n#define portBYTE_ALIGNMENT\t\t\t8\n#define pdFALSE 0\n#define pdTRUE  1\n\n#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\n#if portBYTE_ALIGNMENT == 8\n\t#define portBYTE_ALIGNMENT_MASK ( 0x0007 )\n#endif\n\n#if portBYTE_ALIGNMENT == 4\n\t#define portBYTE_ALIGNMENT_MASK\t( 0x0003 )\n#endif\n\n#if portBYTE_ALIGNMENT == 2\n\t#define portBYTE_ALIGNMENT_MASK\t( 0x0001 )\n#endif\n\n#if portBYTE_ALIGNMENT == 1\n\t#define portBYTE_ALIGNMENT_MASK\t( 0x0000 )\n#endif\n\n#ifndef portBYTE_ALIGNMENT_MASK\n\t#error \"Invalid portBYTE_ALIGNMENT definition\"\n#endif\n\n#define configUSE_MALLOC_FAILED_HOOK\t1\n#define portPOINTER_SIZE_TYPE unsigned int\n\n#define heapMINIMUM_BLOCK_SIZE\t( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )\n\n//#define configADJUSTED_HEAP_SIZE\t( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )\n\n//static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];\nstatic unsigned char *ucHeap;\n\ntypedef struct A_BLOCK_LINK\n{\n\tstruct A_BLOCK_LINK *pxNextFreeBlock;\t//The next free block in the list. \n\tsize_t xBlockSize;\t\t\t\t\t\t//The size of the free block. \n} xBlockLink;\n\nstatic const unsigned short heapSTRUCT_SIZE\t= ( sizeof( xBlockLink ) + portBYTE_ALIGNMENT - ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );\n\n//static const size_t xTotalHeapSize = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );\n\nstatic xBlockLink xStart, *pxEnd = NULL;\n\n//static size_t xFreeBytesRemaining = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );\n\n\n/*-----------------------------------------------------------*/\n\nstatic void prvInsertBlockIntoFreeList( xBlockLink *pxBlockToInsert ) ;//ICACHE_FLASH_ATTR;\n\nstatic void prvHeapInit( void ) ;//ICACHE_FLASH_ATTR;\n\nvoid vApplicationMallocFailedHook( void ) ;//ICACHE_FLASH_ATTR;\n\nvoid *pvPortMalloc( size_t xWantedSize ) ;//ICACHE_FLASH_ATTR;\n\nvoid vPortFree( void *pv ) ;//ICACHE_FLASH_ATTR;\n\nsize_t xPortGetFreeHeapSize( void ) ;//ICACHE_FLASH_ATTR;\n\nvoid vPortInitialiseBlocks( void ) ;//ICACHE_FLASH_ATTR;\n/*-----------------------------------------------------------*/\n\n#endif\n"
  },
  {
    "path": "app/include/netif/etharp.h",
    "content": "/*\n * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\n * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>\n * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#ifndef __NETIF_ETHARP_H__\n#define __NETIF_ETHARP_H__\n\n#include \"lwip/opt.h\"\n\n#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/pbuf.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/ip.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef ETHARP_HWADDR_LEN\n#define ETHARP_HWADDR_LEN     6\n#endif\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct eth_addr {\n  PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\n/** Ethernet header */\nstruct eth_hdr {\n#if ETH_PAD_SIZE\n  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);\n#endif\n  PACK_STRUCT_FIELD(struct eth_addr dest);\n  PACK_STRUCT_FIELD(struct eth_addr src);\n  PACK_STRUCT_FIELD(u16_t type);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)\n\n#if ETHARP_SUPPORT_VLAN\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\n/** VLAN header inserted between ethernet header and payload\n * if 'type' in ethernet header is ETHTYPE_VLAN.\n * See IEEE802.Q */\nstruct eth_vlan_hdr {\n  PACK_STRUCT_FIELD(u16_t tpid);\n  PACK_STRUCT_FIELD(u16_t prio_vid);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#define SIZEOF_VLAN_HDR 4\n#define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF)\n\n#endif /* ETHARP_SUPPORT_VLAN */\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\n/** the ARP message, see RFC 826 (\"Packet format\") */\nstruct etharp_hdr {\n  PACK_STRUCT_FIELD(u16_t hwtype);\n  PACK_STRUCT_FIELD(u16_t proto);\n  PACK_STRUCT_FIELD(u8_t  hwlen);\n  PACK_STRUCT_FIELD(u8_t  protolen);\n  PACK_STRUCT_FIELD(u16_t opcode);\n  PACK_STRUCT_FIELD(struct eth_addr shwaddr);\n  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);\n  PACK_STRUCT_FIELD(struct eth_addr dhwaddr);\n  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#define SIZEOF_ETHARP_HDR 28\n#define SIZEOF_ETHARP_MINSIZE 46\n#define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR)\n#define SIZEOF_ETHARP_WITHPAD (SIZEOF_ETH_HDR + SIZEOF_ETHARP_MINSIZE)\n\n/** 5 seconds period */\n#define ARP_TMR_INTERVAL 5000\n\n#define ETHTYPE_ARP       0x0806\n#define ETHTYPE_IP        0x0800\n#define ETHTYPE_VLAN      0x8100\n#define ETHTYPE_PPPOEDISC 0x8863  /* PPP Over Ethernet Discovery Stage */\n#define ETHTYPE_PPPOE     0x8864  /* PPP Over Ethernet Session Stage */\n#define ETHTYPE_PAE       0x888e\n\n/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables\n * or known to be 32-bit aligned within the protocol header. */\n#ifndef ETHADDR32_COPY\n#define ETHADDR32_COPY(src, dst)  SMEMCPY(src, dst, ETHARP_HWADDR_LEN)\n#endif\n\n/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local\n * variables and known to be 16-bit aligned within the protocol header. */\n#ifndef ETHADDR16_COPY\n#define ETHADDR16_COPY(src, dst)  SMEMCPY(src, dst, ETHARP_HWADDR_LEN)\n#endif\n\n#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */\n\n/** ARP message types (opcodes) */\n#define ARP_REQUEST 1\n#define ARP_REPLY   2\n\n/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type)\n * to a filter function that returns the correct netif when using multiple\n * netifs on one hardware interface where the netif's low-level receive\n * routine cannot decide for the correct netif (e.g. when mapping multiple\n * IP addresses to one hardware interface).\n */\n#ifndef LWIP_ARP_FILTER_NETIF\n#define LWIP_ARP_FILTER_NETIF 0\n#endif\n\n#if ARP_QUEUEING\n/** struct for queueing outgoing packets for unknown address\n  * defined here to be accessed by memp.h\n  */\nstruct etharp_q_entry {\n  struct etharp_q_entry *next;\n  struct pbuf *p;\n};\n#endif /* ARP_QUEUEING */\n\n#define etharp_init() /* Compatibility define, not init needed. */\nvoid etharp_tmr(void)ICACHE_FLASH_ATTR;\ns8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,\n         struct eth_addr **eth_ret, ip_addr_t **ip_ret)ICACHE_FLASH_ATTR;\nerr_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;\nerr_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)ICACHE_FLASH_ATTR;\nerr_t etharp_request(struct netif *netif, ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;\n/** For Ethernet network interfaces, we might want to send \"gratuitous ARP\";\n *  this is an ARP packet sent by a node in order to spontaneously cause other\n *  nodes to update an entry in their ARP cache.\n *  From RFC 3220 \"IP Mobility Support for IPv4\" section 4.6. */\n#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)\nvoid etharp_cleanup_netif(struct netif *netif);\n\n#if ETHARP_SUPPORT_STATIC_ENTRIES\nerr_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)ICACHE_FLASH_ATTR;\nerr_t etharp_remove_static_entry(ip_addr_t *ipaddr)ICACHE_FLASH_ATTR;\n#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */\n\n#if LWIP_AUTOIP\nerr_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,\n                 const struct eth_addr *ethdst_addr,\n                 const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,\n                 const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,\n                 const u16_t opcode)ICACHE_FLASH_ATTR;\n#endif /* LWIP_AUTOIP */\n\n#endif /* LWIP_ARP */\n\nerr_t ethernet_input(struct pbuf *p, struct netif *netif)ICACHE_FLASH_ATTR;\n\n#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0)\n\nextern const struct eth_addr ethbroadcast, ethzero;\n\n#endif /* LWIP_ARP || LWIP_ETHERNET */\n\n#if 0\n/** Ethernet header */\n#ifndef ETHARP_HWADDR_LEN\n#define ETHARP_HWADDR_LEN     6\n#endif\n\n\nstruct eth_addr {\n  PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);\n} PACK_STRUCT_STRUCT;\n\n\nstruct eth_hdr {\n#if ETH_PAD_SIZE\n  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);\n#endif\n  PACK_STRUCT_FIELD(struct eth_addr dest);\n  PACK_STRUCT_FIELD(struct eth_addr src);\n  PACK_STRUCT_FIELD(u16_t type);\n} PACK_STRUCT_STRUCT;\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __NETIF_ARP_H__ */\n"
  },
  {
    "path": "app/include/netif/if_llc.h",
    "content": "/*\t$NetBSD: if_llc.h,v 1.12 1999/11/19 20:41:19 thorpej Exp $\t*/\n\n/*-\n * Copyright (c) 1988, 1993\n *\tThe Regents of the University of California.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\t@(#)if_llc.h\t8.1 (Berkeley) 6/10/93\n * $FreeBSD$\n */\n\n#ifndef _NET_IF_LLC_H_\n#define _NET_IF_LLC_H_\n\n/*\n * IEEE 802.2 Link Level Control headers, for use in conjunction with\n * 802.{3,4,5} media access control methods.\n *\n * Headers here do not use bit fields due to shortcommings in many\n * compilers.\n */\n\nstruct llc {\n\tuint8_t llc_dsap;\n\tuint8_t llc_ssap;\n\tunion {\n\t    struct {\n\t\tuint8_t control;\n\t\tuint8_t format_id;\n\t\tuint8_t class;\n\t\tuint8_t window_x2;\n\t    } __packed type_u;\n\t    struct {\n\t\tuint8_t num_snd_x2;\n\t\tuint8_t num_rcv_x2;\n\t    } __packed type_i;\n\t    struct {\n\t\tuint8_t control;\n\t\tuint8_t num_rcv_x2;\n\t    } __packed type_s;\n\t    struct {\n\t        uint8_t control;\n\t\t/*\n\t\t * We cannot put the following fields in a structure because\n\t\t * the structure rounding might cause padding.\n\t\t */\n\t\tuint8_t frmr_rej_pdu0;\n\t\tuint8_t frmr_rej_pdu1;\n\t\tuint8_t frmr_control;\n\t\tuint8_t frmr_control_ext;\n\t\tuint8_t frmr_cause;\n\t    } __packed type_frmr;\n\t    struct {\n\t\tuint8_t  control;\n\t\tuint8_t  org_code[3];\n\t\tuint16_t ether_type;\n\t    } __packed type_snap;\n\t    struct {\n\t\tuint8_t control;\n\t\tuint8_t control_ext;\n\t    } __packed type_raw;\n\t} __packed llc_un;\n} __packed;\n\nstruct frmrinfo {\n\tuint8_t frmr_rej_pdu0;\n\tuint8_t frmr_rej_pdu1;\n\tuint8_t frmr_control;\n\tuint8_t frmr_control_ext;\n\tuint8_t frmr_cause;\n} __packed;\n\n#define\tllc_control\t\tllc_un.type_u.control\n#define\tllc_control_ext\t\tllc_un.type_raw.control_ext\n#define\tllc_fid\t\t\tllc_un.type_u.format_id\n#define\tllc_class\t\tllc_un.type_u.class\n#define\tllc_window\t\tllc_un.type_u.window_x2\n#define\tllc_frmrinfo \t\tllc_un.type_frmr.frmr_rej_pdu0\n#define\tllc_frmr_pdu0\t\tllc_un.type_frmr.frmr_rej_pdu0\n#define\tllc_frmr_pdu1\t\tllc_un.type_frmr.frmr_rej_pdu1\n#define\tllc_frmr_control\tllc_un.type_frmr.frmr_control\n#define\tllc_frmr_control_ext\tllc_un.type_frmr.frmr_control_ext\n#define\tllc_frmr_cause\t\tllc_un.type_frmr.frmr_cause\n#define\tllc_snap\t\tllc_un.type_snap\n\n/*\n * Don't use sizeof(struct llc_un) for LLC header sizes\n */\n#define LLC_ISFRAMELEN 4\n#define LLC_UFRAMELEN  3\n#define LLC_FRMRLEN    7\n#define LLC_SNAPFRAMELEN 8\n\n#ifdef CTASSERT\nCTASSERT(sizeof (struct llc) == LLC_SNAPFRAMELEN);\n#endif\n\n/*\n * Unnumbered LLC format commands\n */\n#define LLC_UI\t\t0x3\n#define LLC_UI_P\t0x13\n#define LLC_DISC\t0x43\n#define\tLLC_DISC_P\t0x53\n#define LLC_UA\t\t0x63\n#define LLC_UA_P\t0x73\n#define LLC_TEST\t0xe3\n#define LLC_TEST_P\t0xf3\n#define LLC_FRMR\t0x87\n#define\tLLC_FRMR_P\t0x97\n#define LLC_DM\t\t0x0f\n#define\tLLC_DM_P\t0x1f\n#define LLC_XID\t\t0xaf\n#define LLC_XID_P\t0xbf\n#define LLC_SABME\t0x6f\n#define LLC_SABME_P\t0x7f\n\n/*\n * Supervisory LLC commands\n */\n#define\tLLC_RR\t\t0x01\n#define\tLLC_RNR\t\t0x05\n#define\tLLC_REJ\t\t0x09\n\n/*\n * Info format - dummy only\n */\n#define\tLLC_INFO\t0x00\n\n/*\n * ISO PDTR 10178 contains among others\n */\n#define LLC_8021D_LSAP\t0x42\n#define LLC_X25_LSAP\t0x7e\n#define LLC_SNAP_LSAP\t0xaa\n#define LLC_ISO_LSAP\t0xfe\n\n#define RFC1042_LEN\t\t6\n#define RFC1042         {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00}\n#define ETHERNET_TUNNEL {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8}\n\n/*\n *   copied from sys/net/ethernet.h\n */\n#define ETHERTYPE_AARP          0x80F3  /* AppleTalk AARP */\n#define ETHERTYPE_IPX           0x8137  /* Novell (old) NetWare IPX (ECONFIG E option) */\n\n\n\n#endif /* _NET_IF_LLC_H_ */\n"
  },
  {
    "path": "app/include/netif/ppp_oe.h",
    "content": "/*****************************************************************************\n* ppp_oe.h - PPP Over Ethernet implementation for lwIP.\n*\n* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.\n*\n* The authors hereby grant permission to use, copy, modify, distribute,\n* and license this software and its documentation for any purpose, provided\n* that existing copyright notices are retained in all copies and that this\n* notice and the following disclaimer are included verbatim in any \n* distributions. No written agreement, license, or royalty fee is required\n* for any of the authorized uses.\n*\n* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\n* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \n* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*\n******************************************************************************\n* REVISION HISTORY\n*\n* 06-01-01 Marc Boucher <marc@mbsi.ca>\n*   Ported to lwIP.\n*****************************************************************************/\n\n\n\n/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */\n\n/*-\n * Copyright (c) 2002 The NetBSD Foundation, Inc.\n * All rights reserved.\n *\n * This code is derived from software contributed to The NetBSD Foundation\n * by Martin Husemann <martin@NetBSD.org>.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *        This product includes software developed by the NetBSD\n *        Foundation, Inc. and its contributors.\n * 4. Neither the name of The NetBSD Foundation nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\n * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\n * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n#ifndef PPP_OE_H\n#define PPP_OE_H\n\n#include \"lwip/opt.h\"\n\n#if PPPOE_SUPPORT > 0\n\n#include \"netif/etharp.h\"\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct pppoehdr {\n  PACK_STRUCT_FIELD(u8_t vertype);\n  PACK_STRUCT_FIELD(u8_t code);\n  PACK_STRUCT_FIELD(u16_t session);\n  PACK_STRUCT_FIELD(u16_t plen);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct pppoetag {\n  PACK_STRUCT_FIELD(u16_t tag);\n  PACK_STRUCT_FIELD(u16_t len);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n\n#define PPPOE_STATE_INITIAL   0\n#define PPPOE_STATE_PADI_SENT 1\n#define PPPOE_STATE_PADR_SENT 2\n#define PPPOE_STATE_SESSION   3\n#define PPPOE_STATE_CLOSING   4\n/* passive */\n#define PPPOE_STATE_PADO_SENT 1\n\n#define PPPOE_HEADERLEN       sizeof(struct pppoehdr)\n#define PPPOE_VERTYPE         0x11    /* VER=1, TYPE = 1 */\n\n#define PPPOE_TAG_EOL         0x0000  /* end of list */\n#define PPPOE_TAG_SNAME       0x0101  /* service name */\n#define PPPOE_TAG_ACNAME      0x0102  /* access concentrator name */\n#define PPPOE_TAG_HUNIQUE     0x0103  /* host unique */\n#define PPPOE_TAG_ACCOOKIE    0x0104  /* AC cookie */\n#define PPPOE_TAG_VENDOR      0x0105  /* vendor specific */\n#define PPPOE_TAG_RELAYSID    0x0110  /* relay session id */\n#define PPPOE_TAG_SNAME_ERR   0x0201  /* service name error */\n#define PPPOE_TAG_ACSYS_ERR   0x0202  /* AC system error */\n#define PPPOE_TAG_GENERIC_ERR 0x0203  /* gerneric error */\n\n#define PPPOE_CODE_PADI       0x09    /* Active Discovery Initiation */\n#define PPPOE_CODE_PADO       0x07    /* Active Discovery Offer */\n#define PPPOE_CODE_PADR       0x19    /* Active Discovery Request */\n#define PPPOE_CODE_PADS       0x65    /* Active Discovery Session confirmation */\n#define PPPOE_CODE_PADT       0xA7    /* Active Discovery Terminate */\n\n#ifndef ETHERMTU\n#define ETHERMTU 1500\n#endif\n\n/* two byte PPP protocol discriminator, then IP data */\n#define PPPOE_MAXMTU          (ETHERMTU-PPPOE_HEADERLEN-2)\n\n#ifndef PPPOE_MAX_AC_COOKIE_LEN\n#define PPPOE_MAX_AC_COOKIE_LEN   64\n#endif\n\nstruct pppoe_softc {\n  struct pppoe_softc *next;\n  struct netif *sc_ethif;      /* ethernet interface we are using */\n  int sc_pd;                   /* ppp unit number */\n  void (*sc_linkStatusCB)(int pd, int up);\n\n  int sc_state;                /* discovery phase or session connected */\n  struct eth_addr sc_dest;     /* hardware address of concentrator */\n  u16_t sc_session;            /* PPPoE session id */\n\n#ifdef PPPOE_TODO\n  char *sc_service_name;       /* if != NULL: requested name of service */\n  char *sc_concentrator_name;  /* if != NULL: requested concentrator id */\n#endif /* PPPOE_TODO */\n  u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */\n  size_t sc_ac_cookie_len;     /* length of cookie data */\n#ifdef PPPOE_SERVER\n  u8_t *sc_hunique;            /* content of host unique we must echo back */\n  size_t sc_hunique_len;       /* length of host unique */\n#endif\n  int sc_padi_retried;         /* number of PADI retries already done */\n  int sc_padr_retried;         /* number of PADR retries already done */\n};\n\n\n#define pppoe_init() /* compatibility define, no initialization needed */\n\nerr_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr);\nerr_t pppoe_destroy(struct netif *ifp);\n\nint pppoe_connect(struct pppoe_softc *sc);\nvoid pppoe_disconnect(struct pppoe_softc *sc);\n\nvoid pppoe_disc_input(struct netif *netif, struct pbuf *p);\nvoid pppoe_data_input(struct netif *netif, struct pbuf *p);\n\nerr_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);\n\n/** used in ppp.c */\n#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN)\n\n#endif /* PPPOE_SUPPORT */\n\n#endif /* PPP_OE_H */\n"
  },
  {
    "path": "app/include/netif/wlan_lwip_if.h",
    "content": "/*\n *  Copyright (c) 2010-2011 \tEspressif System\n *   \n*/\n\n#ifndef _WLAN_LWIP_IF_H_\n#define _WLAN_LWIP_IF_H_\n\n#define LWIP_IF0_PRIO   28\n#define LWIP_IF1_PRIO   29\n\nenum {\n\tSIG_LWIP_RX = 0, \n};\n\nstruct netif * eagle_lwip_if_alloc(struct ieee80211_conn *conn, const uint8 *macaddr, struct ip_info *info);\nstruct netif * eagle_lwip_getif(uint8 index);\n\n#ifndef IOT_SIP_MODE\nsint8 ieee80211_output_pbuf(struct netif *ifp, struct pbuf* pb);\n#else\nsint8 ieee80211_output_pbuf(struct ieee80211_conn *conn, esf_buf *eb);\n#endif\n\n#endif /*  _WLAN_LWIP_IF_H_ */\n"
  },
  {
    "path": "app/include/pp/esf_buf.h",
    "content": "/* \n * copyright (c) 2008 - 2012 Espressif System \n * \n * esf buffer data structure\n */\n\n#ifndef _ESF_BUF_H_\n#define _ESF_BUF_H_\n\n#define EP_OFFSET       36  /* see comments in pbuf.h */\n\n#endif /* _ESF_BUF_H_ */\n"
  },
  {
    "path": "app/include/serial_number.h",
    "content": "#ifndef __SERIAL_NUMBER_H\n#define __SERIAL_NUMBER_H\n\n#define SERIAL_NUMBER \"865732\"\n\n#endif"
  },
  {
    "path": "app/include/ssl/app/espconn_secure.h",
    "content": "#ifndef __ESPCONN_ENCRY_H__\n#define __ESPCONN_ENCRY_H__\n\n#include \"espconn/espconn.h\"\n\n/******************************************************************************\n * FunctionName : espconn_encry_connect\n * Description  : The function given as connection\n * Parameters   : espconn -- the espconn used to connect with the host\n * Returns      : none\n*******************************************************************************/\n\nsint8 espconn_secure_connect(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_encry_disconnect\n * Description  : The function given as the disconnection\n * Parameters   : espconn -- the espconn used to disconnect with the host\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_secure_disconnect(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_encry_sent\n * Description  : sent data for client or server\n * Parameters   : espconn -- espconn to set for client or server\n * \t\t\t\t  psent -- data to send\n *                length -- length of data to send\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length);\n\n/******************************************************************************\n * FunctionName : espconn_secure_accept\n * Description  : The function given as the listen\n * Parameters   : espconn -- the espconn used to listen the connection\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_secure_accept(struct espconn *espconn);\n\n#endif\n\n\n"
  },
  {
    "path": "app/include/ssl/app/espconn_ssl.h",
    "content": "#ifndef ESPCONN_SSL_CLIENT_H\n#define ESPCONN_SSL_CLIENT_H\n\n#include \"ssl/ssl_ssl.h\"\n#include \"ssl/ssl_tls1.h\"\n\n#include \"lwip/app/espconn.h\"\n\ntypedef struct _ssl_msg {\n    SSL_CTX *ssl_ctx;\n    SSL *ssl;\n    bool quiet;\n    char *private_key_file;\n    uint8_t session_id[SSL_SESSION_ID_SIZE];\n    u16_t pkt_length;\n} ssl_msg;\n\n/******************************************************************************\n * FunctionName : sslserver_start\n * Description  : Initialize the server: set up a listen PCB and bind it to \n *                the defined port\n * Parameters   : espconn -- the espconn used to build client\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_ssl_server(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_ssl_client\n * Description  : Initialize the client: set up a connect PCB and bind it to \n *                the defined port\n * Parameters   : espconn -- the espconn used to build client\n * Returns      : none\n*******************************************************************************/\n\nextern sint8 espconn_ssl_client(struct espconn *espconn);\n\n/******************************************************************************\n * FunctionName : espconn_ssl_write\n * Description  : sent data for client or server\n * Parameters   : void *arg -- client or server to send\n * \t\t\t\t  uint8* psent -- Data to send\n *                uint16 length -- Length of data to send\n * Returns      : none\n*******************************************************************************/\n\nextern void espconn_ssl_sent(void *arg, uint8 *psent, uint16 length);\n\n/******************************************************************************\n * FunctionName : espconn_ssl_disconnect\n * Description  : A new incoming connection has been disconnected.\n * Parameters   : espconn -- the espconn used to disconnect with host\n * Returns      : none\n*******************************************************************************/\n\nextern void espconn_ssl_disconnect(espconn_msg *pdis);\n\n#endif\n\n"
  },
  {
    "path": "app/include/ssl/cert.h",
    "content": "unsigned char default_certificate[] = {\n  0x30, 0x82, 0x01, 0x82, 0x30, 0x81, 0xec, 0x02, 0x09, 0x00, 0x88, 0xf2,\n  0x5f, 0x46, 0x12, 0x2e, 0x3d, 0x3a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,\n  0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x1c, 0x31,\n  0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x77, 0x77,\n  0x77, 0x2e, 0x65, 0x73, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x66, 0x2e,\n  0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x32,\n  0x34, 0x31, 0x30, 0x32, 0x32, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x32, 0x38,\n  0x30, 0x33, 0x30, 0x32, 0x31, 0x30, 0x32, 0x32, 0x33, 0x33, 0x5a, 0x30,\n  0x34, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x09,\n  0x65, 0x73, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x66, 0x31, 0x1e, 0x30,\n  0x1c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x15, 0x65, 0x73, 0x70, 0x72,\n  0x65, 0x73, 0x73, 0x69, 0x66, 0x20, 0x49, 0x6f, 0x54, 0x20, 0x70, 0x72,\n  0x6f, 0x6a, 0x65, 0x63, 0x74, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a,\n  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b,\n  0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xb9, 0x83, 0x30, 0xca, 0xfb, 0xec,\n  0x11, 0x9e, 0x94, 0xb7, 0x89, 0xf2, 0x84, 0x2c, 0xda, 0xe1, 0x9a, 0x53,\n  0x3a, 0x1b, 0x6e, 0xc9, 0x85, 0x81, 0xf9, 0xa3, 0x41, 0xdb, 0xe2, 0x82,\n  0x3b, 0xfa, 0x80, 0x22, 0x3b, 0x81, 0x6d, 0x25, 0x73, 0x7e, 0xf6, 0x49,\n  0xcc, 0x69, 0x3c, 0x6c, 0xd8, 0x05, 0xfb, 0x92, 0x02, 0xcf, 0x19, 0x2a,\n  0x10, 0x7d, 0x69, 0x7a, 0xd8, 0x9d, 0xd3, 0xcf, 0x6c, 0xef, 0x02, 0x03,\n  0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,\n  0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x2d, 0x63,\n  0x58, 0x21, 0xe3, 0x8b, 0x37, 0x0d, 0x28, 0x68, 0x11, 0x0e, 0x4d, 0xdd,\n  0xf3, 0xea, 0xdb, 0xec, 0xd7, 0x09, 0x47, 0x2c, 0xa1, 0xd8, 0xd1, 0x71,\n  0x83, 0x11, 0xb4, 0x17, 0xbc, 0x83, 0xea, 0x5a, 0xd6, 0x73, 0x02, 0x25,\n  0x87, 0x01, 0x76, 0xfc, 0x59, 0x1a, 0xcf, 0xd9, 0x49, 0xc9, 0xf9, 0x1f,\n  0x5c, 0x3b, 0x24, 0x6a, 0x5c, 0xa5, 0xca, 0xe6, 0x5d, 0x34, 0x5b, 0x5f,\n  0xcf, 0x56, 0x9c, 0x71, 0xd2, 0x6b, 0xdd, 0x1f, 0x15, 0xae, 0x4d, 0xf1,\n  0xca, 0x35, 0xc8, 0xdd, 0x93, 0x1b, 0x58, 0x1e, 0x94, 0x08, 0xcf, 0xa0,\n  0x20, 0xb9, 0x75, 0xa5, 0x4c, 0x77, 0xf5, 0x7f, 0xed, 0xd5, 0xcd, 0x53,\n  0xaa, 0x87, 0xa6, 0x3c, 0xf5, 0x72, 0xd8, 0xd2, 0xb0, 0xf7, 0x11, 0xb0,\n  0x0e, 0xe9, 0x41, 0xd6, 0x8e, 0xd9, 0x07, 0xf8, 0xed, 0xf8, 0x67, 0x7f,\n  0x28, 0x18, 0xf0, 0x1b, 0x29, 0x11\n};\nunsigned int default_certificate_len = 390;\n"
  },
  {
    "path": "app/include/ssl/private_key.h",
    "content": "unsigned char default_private_key[] = {\n  0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xb9, 0x83,\n  0x30, 0xca, 0xfb, 0xec, 0x11, 0x9e, 0x94, 0xb7, 0x89, 0xf2, 0x84, 0x2c,\n  0xda, 0xe1, 0x9a, 0x53, 0x3a, 0x1b, 0x6e, 0xc9, 0x85, 0x81, 0xf9, 0xa3,\n  0x41, 0xdb, 0xe2, 0x82, 0x3b, 0xfa, 0x80, 0x22, 0x3b, 0x81, 0x6d, 0x25,\n  0x73, 0x7e, 0xf6, 0x49, 0xcc, 0x69, 0x3c, 0x6c, 0xd8, 0x05, 0xfb, 0x92,\n  0x02, 0xcf, 0x19, 0x2a, 0x10, 0x7d, 0x69, 0x7a, 0xd8, 0x9d, 0xd3, 0xcf,\n  0x6c, 0xef, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x1d, 0x13, 0x92,\n  0xf2, 0x3d, 0xca, 0x22, 0x78, 0xd8, 0x96, 0x6b, 0xe8, 0xb7, 0x0e, 0xd0,\n  0xbf, 0xcb, 0x90, 0x7f, 0xeb, 0x0c, 0xd2, 0x49, 0x3a, 0xb6, 0x06, 0x00,\n  0xac, 0x96, 0x34, 0x13, 0x72, 0x4b, 0x8c, 0xd2, 0xb9, 0x35, 0xf5, 0x64,\n  0x18, 0xb2, 0x47, 0x5b, 0x9f, 0xbb, 0xf2, 0x5b, 0x2f, 0x66, 0x78, 0x2d,\n  0x0a, 0x76, 0x44, 0xc5, 0x4f, 0xdb, 0x7d, 0x13, 0xcf, 0xa5, 0x08, 0xdc,\n  0x01, 0x02, 0x21, 0x00, 0xdf, 0x9a, 0x89, 0xd0, 0xef, 0x23, 0xcf, 0x12,\n  0xac, 0x8a, 0x63, 0x1a, 0x8c, 0xc0, 0x3f, 0xf4, 0x38, 0x52, 0x3c, 0x9f,\n  0x19, 0x0a, 0x37, 0xd2, 0xcb, 0x5d, 0xeb, 0xb6, 0x2a, 0x33, 0xb0, 0x91,\n  0x02, 0x21, 0x00, 0xd4, 0x63, 0xd9, 0x6a, 0x18, 0x5b, 0xe8, 0xa8, 0x57,\n  0x4d, 0xd1, 0x9a, 0xa8, 0xd7, 0xe1, 0x65, 0x75, 0xb3, 0xb9, 0x5c, 0x94,\n  0x14, 0xca, 0x98, 0x41, 0x47, 0x9c, 0x0a, 0x22, 0x38, 0x05, 0x7f, 0x02,\n  0x20, 0x6a, 0xce, 0xfd, 0xef, 0xe0, 0x9b, 0x61, 0x49, 0x91, 0x43, 0x95,\n  0x6d, 0x54, 0x38, 0x6d, 0x14, 0x32, 0x67, 0x0d, 0xf0, 0x0d, 0x5c, 0xf5,\n  0x27, 0x6a, 0xdf, 0x55, 0x3d, 0xb1, 0xd0, 0xf9, 0x11, 0x02, 0x21, 0x00,\n  0xba, 0x94, 0xa0, 0xf9, 0xb0, 0x3e, 0x85, 0x8b, 0xe5, 0x6e, 0x4a, 0x95,\n  0x88, 0x80, 0x65, 0xd5, 0x00, 0xea, 0x8b, 0x0b, 0x46, 0x57, 0x61, 0x87,\n  0x11, 0xc9, 0xfb, 0xcd, 0x77, 0x34, 0x29, 0xb7, 0x02, 0x20, 0x06, 0x8d,\n  0x41, 0x11, 0x47, 0x93, 0xcb, 0xad, 0xda, 0x5d, 0xe1, 0x9d, 0x49, 0x8d,\n  0xe0, 0xab, 0x48, 0xe6, 0x18, 0x28, 0x4a, 0x94, 0xae, 0xf9, 0xad, 0xc5,\n  0x5b, 0x0b, 0x15, 0xc6, 0x73, 0x17\n};\nunsigned int default_private_key_len = 318;\n"
  },
  {
    "path": "app/include/ssl/ssl_bigint.h",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef BIGINT_HEADER\n#define BIGINT_HEADER\n\n#include \"ssl/ssl_crypto.h\"\n\nBI_CTX *bi_initialize(void);\nvoid bi_terminate(BI_CTX *ctx);\nvoid bi_permanent(bigint *bi);\nvoid bi_depermanent(bigint *bi);\nvoid bi_clear_cache(BI_CTX *ctx);\nvoid bi_free(BI_CTX *ctx, bigint *bi);\nbigint *bi_copy(bigint *bi);\nbigint *bi_clone(BI_CTX *ctx, const bigint *bi);\nvoid bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);\nbigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);\nbigint *int_to_bi(BI_CTX *ctx, comp i);\n\n/* the functions that actually do something interesting */\nbigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);\nbigint *bi_subtract(BI_CTX *ctx, bigint *bia, \n        bigint *bib, int *is_negative);\nbigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);\nbigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);\nbigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);\nbigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);\nint bi_compare(bigint *bia, bigint *bib);\nvoid bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);\nvoid bi_free_mod(BI_CTX *ctx, int mod_offset);\n\n#ifdef CONFIG_SSL_FULL_MODE\nvoid bi_print(const char *label, bigint *bi);\nbigint *bi_str_import(BI_CTX *ctx, const char *data);\n#endif\n\n/**\n * @def bi_mod\n * Find the residue of B. bi_set_mod() must be called before hand.\n */\n#define bi_mod(A, B)      bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)\n\n/**\n * bi_residue() is technically the same as bi_mod(), but it uses the\n * appropriate reduction technique (which is bi_mod() when doing classical\n * reduction).\n */\n#if defined(CONFIG_BIGINT_MONTGOMERY)\n#define bi_residue(A, B)         bi_mont(A, B)\nbigint *bi_mont(BI_CTX *ctx, bigint *bixy);\n#elif defined(CONFIG_BIGINT_BARRETT)\n#define bi_residue(A, B)         bi_barrett(A, B)\nbigint *bi_barrett(BI_CTX *ctx, bigint *bi);\n#else /* if defined(CONFIG_BIGINT_CLASSICAL) */\n#define bi_residue(A, B)         bi_mod(A, B)\n#endif\n\n#ifdef CONFIG_BIGINT_SQUARE\nbigint *bi_square(BI_CTX *ctx, bigint *bi);\n#else\n#define bi_square(A, B)     bi_multiply(A, bi_copy(B), B)\n#endif\n\n#ifdef CONFIG_BIGINT_CRT\nbigint *bi_crt(BI_CTX *ctx, bigint *bi,\n        bigint *dP, bigint *dQ,\n        bigint *p, bigint *q,\n        bigint *qInv);\n#endif\n\n#endif\n"
  },
  {
    "path": "app/include/ssl/ssl_bigint_impl.h",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef BIGINT_IMPL_HEADER\n#define BIGINT_IMPL_HEADER\n\n/* Maintain a number of precomputed variables when doing reduction */\n#define BIGINT_M_OFFSET     0    /**< Normal modulo offset. */\n#ifdef CONFIG_BIGINT_CRT\n#define BIGINT_P_OFFSET     1    /**< p modulo offset. */\n#define BIGINT_Q_OFFSET     2    /**< q module offset. */\n#define BIGINT_NUM_MODS     3    /**< The number of modulus constants used. */\n#else\n#define BIGINT_NUM_MODS     1    \n#endif\n\n/* Architecture specific functions for big ints */\n#if defined(CONFIG_INTEGER_8BIT)\n#define COMP_RADIX          256U       /**< Max component + 1 */\n#define COMP_MAX            0xFFFFU/**< (Max dbl comp -1) */\n#define COMP_BIT_SIZE       8   /**< Number of bits in a component. */\n#define COMP_BYTE_SIZE      1   /**< Number of bytes in a component. */\n#define COMP_NUM_NIBBLES    2   /**< Used For diagnostics only. */\ntypedef uint8_t comp;\t        /**< A single precision component. */\ntypedef uint16_t long_comp;     /**< A double precision component. */\ntypedef int16_t slong_comp;     /**< A signed double precision component. */\n#elif defined(CONFIG_INTEGER_16BIT)\n#define COMP_RADIX          65536U       /**< Max component + 1 */\n#define COMP_MAX            0xFFFFFFFFU/**< (Max dbl comp -1) */\n#define COMP_BIT_SIZE       16  /**< Number of bits in a component. */\n#define COMP_BYTE_SIZE      2   /**< Number of bytes in a component. */\n#define COMP_NUM_NIBBLES    4   /**< Used For diagnostics only. */\ntypedef uint16_t comp;\t        /**< A single precision component. */\ntypedef uint32_t long_comp;     /**< A double precision component. */\ntypedef int32_t slong_comp;     /**< A signed double precision component. */\n#else /* regular 32 bit */\n#ifdef WIN32\n#define COMP_RADIX          4294967296i64         \n#define COMP_MAX            0xFFFFFFFFFFFFFFFFui64\n#else\n#define COMP_RADIX          4294967296ULL         /**< Max component + 1 */\n#define COMP_MAX            0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */\n#endif\n#define COMP_BIT_SIZE       32  /**< Number of bits in a component. */\n#define COMP_BYTE_SIZE      4   /**< Number of bytes in a component. */\n#define COMP_NUM_NIBBLES    8   /**< Used For diagnostics only. */\ntypedef uint32_t comp;\t        /**< A single precision component. */\ntypedef uint64_t long_comp;     /**< A double precision component. */\ntypedef sint64_t slong_comp;     /**< A signed double precision component. */\n#endif\n\n/**\n * @struct  _bigint\n * @brief A big integer basic object\n */\nstruct _bigint\n{\n    struct _bigint* next;       /**< The next bigint in the cache. */\n    short size;                 /**< The number of components in this bigint. */\n    short max_comps;            /**< The heapsize allocated for this bigint */\n    int refs;                   /**< An internal reference count. */\n    comp* comps;                /**< A ptr to the actual component data */\n};\n\ntypedef struct _bigint bigint;  /**< An alias for _bigint */\n\n/**\n * Maintains the state of the cache, and a number of variables used in \n * reduction.\n */\ntypedef struct /**< A big integer \"session\" context. */\n{\n    bigint *active_list;                    /**< Bigints currently used. */\n    bigint *free_list;                      /**< Bigints not used. */\n    bigint *bi_radix;                       /**< The radix used. */\n    bigint *bi_mod[BIGINT_NUM_MODS];        /**< modulus */\n\n#if defined(CONFIG_BIGINT_MONTGOMERY)\n    bigint *bi_RR_mod_m[BIGINT_NUM_MODS];   /**< R^2 mod m */\n    bigint *bi_R_mod_m[BIGINT_NUM_MODS];    /**< R mod m */\n    comp N0_dash[BIGINT_NUM_MODS];\n#elif defined(CONFIG_BIGINT_BARRETT)\n    bigint *bi_mu[BIGINT_NUM_MODS];         /**< Storage for mu */\n#endif\n    bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */\n    bigint **g;                 /**< Used by sliding-window. */\n    int window;                 /**< The size of the sliding window */\n    int active_count;           /**< Number of active bigints. */\n    int free_count;             /**< Number of free bigints. */\n\n#ifdef CONFIG_BIGINT_MONTGOMERY\n    uint8_t use_classical;      /**< Use classical reduction. */\n#endif\n    uint8_t mod_offset;         /**< The mod offset we are using */\n} BI_CTX;\n\n#ifndef WIN32\n#define max(a,b) ((a)>(b)?(a):(b))  /**< Find the maximum of 2 numbers. */\n#define min(a,b) ((a)<(b)?(a):(b))  /**< Find the minimum of 2 numbers. */\n#endif\n\n#define PERMANENT           0x7FFF55AA  /**< A magic number for permanents. */\n\n#endif\n"
  },
  {
    "path": "app/include/ssl/ssl_cert.h",
    "content": "unsigned char default_certificate[] = {\n  0x30, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0x40, 0x02, 0x09, 0x00, 0xab,\n  0x08, 0x18, 0xa7, 0x03, 0x07, 0x27, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a,\n  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x34,\n  0x31, 0x32, 0x30, 0x30, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x29, 0x61,\n  0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,\n  0x20, 0x44, 0x6f, 0x64, 0x67, 0x79, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,\n  0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f,\n  0x72, 0x69, 0x74, 0x79, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x31, 0x32,\n  0x32, 0x36, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x32,\n  0x34, 0x30, 0x39, 0x30, 0x33, 0x32, 0x32, 0x33, 0x33, 0x33, 0x39, 0x5a,\n  0x30, 0x2c, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,\n  0x0d, 0x61, 0x78, 0x54, 0x4c, 0x53, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65,\n  0x63, 0x74, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,\n  0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81,\n  0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,\n  0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02,\n  0x81, 0x81, 0x00, 0xcd, 0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76,\n  0xd4, 0x13, 0x30, 0x0e, 0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f,\n  0x51, 0x09, 0x9d, 0x29, 0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90,\n  0x80, 0xa1, 0x71, 0xdf, 0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14,\n  0x90, 0x0a, 0xf9, 0xb7, 0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d,\n  0x57, 0x41, 0x86, 0x60, 0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46,\n  0x1b, 0xf6, 0xa2, 0x84, 0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa,\n  0x91, 0xf8, 0x61, 0x04, 0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a,\n  0xcc, 0x31, 0x01, 0x14, 0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82,\n  0xd6, 0xc6, 0xc4, 0xbe, 0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32,\n  0x7a, 0x86, 0x0e, 0x91, 0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02,\n  0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,\n  0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40,\n  0xb4, 0x94, 0x9a, 0xa8, 0x89, 0x72, 0x1d, 0x07, 0xe5, 0xb3, 0x6b, 0x88,\n  0x21, 0xc2, 0x38, 0x36, 0x9e, 0x7a, 0x8c, 0x49, 0x48, 0x68, 0x0c, 0x06,\n  0xe8, 0xdb, 0x1f, 0x4e, 0x05, 0xe6, 0x31, 0xe3, 0xfd, 0xe6, 0x0d, 0x6b,\n  0xd8, 0x13, 0x17, 0xe0, 0x2d, 0x0d, 0xb8, 0x7e, 0xcb, 0x20, 0x6c, 0xa8,\n  0x73, 0xa7, 0xfd, 0xe3, 0xa7, 0xfa, 0xf3, 0x02, 0x60, 0x78, 0x1f, 0x13,\n  0x40, 0x45, 0xee, 0x75, 0xf5, 0x10, 0xfd, 0x8f, 0x68, 0x74, 0xd4, 0xac,\n  0xae, 0x04, 0x09, 0x55, 0x2c, 0xdb, 0xd8, 0x07, 0x07, 0x65, 0x69, 0x27,\n  0x6e, 0xbf, 0x5e, 0x61, 0x40, 0x56, 0x8b, 0xd7, 0x33, 0x3b, 0xff, 0x6e,\n  0x53, 0x7e, 0x9d, 0x3f, 0xc0, 0x40, 0x3a, 0xab, 0xa0, 0x50, 0x4e, 0x80,\n  0x47, 0x46, 0x0d, 0x1e, 0xdb, 0x4c, 0xf1, 0x1b, 0x5d, 0x3c, 0x2a, 0x54,\n  0xa7, 0x4d, 0xfa, 0x7b, 0x72, 0x66, 0xc5\n};\nunsigned int default_certificate_len = 475;\n"
  },
  {
    "path": "app/include/ssl/ssl_config.h",
    "content": "/*\n * Automatically generated header file: don't edit\n */\n\n#define HAVE_DOT_CONFIG 1\n#undef CONFIG_PLATFORM_LINUX\n#define CONFIG_PLATFORM_CYGWIN 1\n#undef CONFIG_PLATFORM_WIN32\n\n/*\n * General Configuration\n */\n#define PREFIX \"/usr/local\"\n#define CONFIG_DEBUG 1\n#undef CONFIG_STRIP_UNWANTED_SECTIONS\n#undef CONFIG_VISUAL_STUDIO_7_0\n#undef CONFIG_VISUAL_STUDIO_8_0\n#undef CONFIG_VISUAL_STUDIO_10_0\n#define CONFIG_VISUAL_STUDIO_7_0_BASE \"\"\n#define CONFIG_VISUAL_STUDIO_8_0_BASE \"\"\n#define CONFIG_VISUAL_STUDIO_10_0_BASE \"\"\n#define CONFIG_EXTRA_CFLAGS_OPTIONS \"\"\n#define CONFIG_EXTRA_LDFLAGS_OPTIONS \"\"\n\n/*\n * SSL Library\n */\n#undef CONFIG_SSL_SERVER_ONLY\n#undef CONFIG_SSL_CERT_VERIFICATION\n#undef CONFIG_SSL_ENABLE_CLIENT\n#define CONFIG_SSL_FULL_MODE 1\n#undef CONFIG_SSL_SKELETON_MODE\n#undef CONFIG_SSL_PROT_LOW\n#define CONFIG_SSL_PROT_MEDIUM 1\n#undef CONFIG_SSL_PROT_HIGH\n#define CONFIG_SSL_USE_DEFAULT_KEY\n#define CONFIG_SSL_PRIVATE_KEY_LOCATION \"\"\n#define CONFIG_SSL_PRIVATE_KEY_PASSWORD \"\"\n#define CONFIG_SSL_X509_CERT_LOCATION \"\"\n#undef CONFIG_SSL_GENERATE_X509_CERT\n#define CONFIG_SSL_X509_COMMON_NAME \"\"\n#define CONFIG_SSL_X509_ORGANIZATION_NAME \"\"\n#define CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME \"\"\n#undef CONFIG_SSL_ENABLE_V23_HANDSHAKE\n#define CONFIG_SSL_HAS_PEM 1\n#undef CONFIG_SSL_USE_PKCS12\n#define CONFIG_SSL_EXPIRY_TIME 24\n#define CONFIG_X509_MAX_CA_CERTS 150\n#define CONFIG_SSL_MAX_CERTS 3\n#undef CONFIG_SSL_CTX_MUTEXING\n//#define CONFIG_USE_DEV_URANDOM 1\n#undef CONFIG_WIN32_USE_CRYPTO_LIB\n#undef CONFIG_OPENSSL_COMPATIBLE\n#undef CONFIG_PERFORMANCE_TESTING\n#define CONFIG_SSL_TEST 1\n#undef CONFIG_AXTLSWRAP\n#define CONFIG_AXHTTPD 1\n\n/*\n * Axhttpd Configuration\n */\n#undef CONFIG_HTTP_STATIC_BUILD\n#define CONFIG_HTTP_PORT 80\n#define CONFIG_HTTP_HTTPS_PORT 443\n#define CONFIG_HTTP_SESSION_CACHE_SIZE 5\n#define CONFIG_HTTP_WEBROOT \"../www\"\n#define CONFIG_HTTP_TIMEOUT 300\n\n/*\n * CGI\n */\n#undef CONFIG_HTTP_HAS_CGI \n#define CONFIG_HTTP_CGI_EXTENSIONS \".lua,.lp,.php\"\n#define CONFIG_HTTP_ENABLE_LUA 1\n#define CONFIG_HTTP_LUA_PREFIX \"/usr\"\n#undef CONFIG_HTTP_BUILD_LUA\n#define CONFIG_HTTP_CGI_LAUNCHER \"/usr/bin/cgi\"\n#define CONFIG_HTTP_DIRECTORIES 1\n#define CONFIG_HTTP_HAS_AUTHORIZATION 1\n#undef CONFIG_HTTP_HAS_IPV6\n#undef CONFIG_HTTP_ENABLE_DIFFERENT_USER\n#define CONFIG_HTTP_USER \"\"\n#define CONFIG_HTTP_VERBOSE 0\n#undef CONFIG_HTTP_IS_DAEMON\n\n/*\n * Language Bindings\n */\n#undef CONFIG_BINDINGS\n#undef CONFIG_CSHARP_BINDINGS\n#undef CONFIG_VBNET_BINDINGS\n#define CONFIG_DOT_NET_FRAMEWORK_BASE \"\"\n#undef CONFIG_JAVA_BINDINGS\n#define CONFIG_JAVA_HOME \"\"\n#undef CONFIG_PERL_BINDINGS\n#define CONFIG_PERL_CORE \"\"\n#define CONFIG_PERL_LIB \"\"\n#undef CONFIG_LUA_BINDINGS\n#define CONFIG_LUA_CORE \"\"\n\n/*\n * Samples\n */\n#define CONFIG_SAMPLES 1\n#define CONFIG_C_SAMPLES 1\n#undef CONFIG_CSHARP_SAMPLES\n#undef CONFIG_VBNET_SAMPLES\n#undef CONFIG_JAVA_SAMPLES\n#undef CONFIG_PERL_SAMPLES\n#undef CONFIG_LUA_SAMPLES\n\n/*\n * BigInt Options\n */\n#undef CONFIG_BIGINT_CLASSICAL\n#undef CONFIG_BIGINT_MONTGOMERY\n#define CONFIG_BIGINT_BARRETT 1\n#define CONFIG_BIGINT_CRT 1\n#undef CONFIG_BIGINT_KARATSUBA\n#define MUL_KARATSUBA_THRESH \n#define SQU_KARATSUBA_THRESH \n#define CONFIG_BIGINT_SLIDING_WINDOW 1\n#define CONFIG_BIGINT_SQUARE 1\n#define CONFIG_BIGINT_CHECK_ON 1\n#define CONFIG_INTEGER_32BIT 1\n#undef CONFIG_INTEGER_16BIT\n#undef CONFIG_INTEGER_8BIT\n"
  },
  {
    "path": "app/include/ssl/ssl_crypto.h",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @file crypto.h\n */\n\n#ifndef HEADER_CRYPTO_H\n#define HEADER_CRYPTO_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"ssl/ssl_config.h\"\n#include \"ssl/ssl_bigint_impl.h\"\n#include \"ssl/ssl_bigint.h\"\n\n#ifndef STDCALL\n#define STDCALL\n#endif\n#ifndef EXP_FUNC\n#define EXP_FUNC\n#endif\n\n\n/* enable features based on a 'super-set' capbaility. */\n#if defined(CONFIG_SSL_FULL_MODE) \n#define CONFIG_SSL_ENABLE_CLIENT\n#define CONFIG_SSL_CERT_VERIFICATION\n#elif defined(CONFIG_SSL_ENABLE_CLIENT)\n#define CONFIG_SSL_CERT_VERIFICATION\n#endif\n\n/**************************************************************************\n * AES declarations \n **************************************************************************/\n\n#define AES_MAXROUNDS\t\t\t14\n#define AES_BLOCKSIZE           16\n#define AES_IV_SIZE             16\n\ntypedef struct aes_key_st \n{\n    uint16_t rounds;\n    uint16_t key_size;\n    uint32_t ks[(AES_MAXROUNDS+1)*8];\n    uint8_t iv[AES_IV_SIZE];\n} AES_CTX;\n\ntypedef enum\n{\n    AES_MODE_128,\n    AES_MODE_256\n} AES_MODE;\n\nvoid AES_set_key(AES_CTX *ctx, const uint8_t *key, \n        const uint8_t *iv, AES_MODE mode);\nvoid AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, \n        uint8_t *out, int length);\nvoid AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);\nvoid AES_convert_key(AES_CTX *ctx);\n\n/**************************************************************************\n * RC4 declarations \n **************************************************************************/\n\ntypedef struct \n{\n    uint8_t x, y, m[256];\n} RC4_CTX;\n\nvoid RC4_setup(RC4_CTX *s, const uint8_t *key, int length);\nvoid RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);\n\n/**************************************************************************\n * SHA1 declarations \n **************************************************************************/\n\n#define SHA1_SIZE   20\n\n/*\n *  This structure will hold context information for the SHA-1\n *  hashing operation\n */\ntypedef struct \n{\n    uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */\n    uint32_t Length_Low;            /* Message length in bits */\n    uint32_t Length_High;           /* Message length in bits */\n    uint16_t Message_Block_Index;   /* Index into message block array   */\n    uint8_t Message_Block[64];      /* 512-bit message blocks */\n} SHA1_CTX;\n\nvoid SHA1_Init(SHA1_CTX *);\nvoid SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);\nvoid SHA1_Final(uint8_t *digest, SHA1_CTX *);\n\n/**************************************************************************\n * MD2 declarations \n **************************************************************************/\n\n#define MD2_SIZE 16\n\ntypedef struct\n{\n    unsigned char cksum[16];    /* checksum of the data block */\n    unsigned char state[48];    /* intermediate digest state */\n    unsigned char buffer[16];   /* data block being processed */\n    int left;                   /* amount of data in buffer */\n} MD2_CTX;\n\nEXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);\nEXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);\nEXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);\n\n/**************************************************************************\n * MD5 declarations \n **************************************************************************/\n\n#define MD5_SIZE    16\n\ntypedef struct \n{\n  uint32_t state[4];        /* state (ABCD) */\n  uint32_t count[2];        /* number of bits, modulo 2^64 (lsb first) */\n  uint8_t buffer[64];       /* input buffer */\n} MD5_CTX;\n\nEXP_FUNC void STDCALL MD5_Init(MD5_CTX *);\nEXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);\nEXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);\n\n/**************************************************************************\n * HMAC declarations \n **************************************************************************/\nvoid ssl_hmac_md5(const uint8_t *msg, int length, const uint8_t *key, \n        int key_len, uint8_t *digest);// fix hmac_md5 to ssl_hmac_md5, discriminate ieee80211\nvoid ssl_hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, \n        int key_len, uint8_t *digest);// fix hmac_md5 to ssl_hmac_sha1, discriminate ieee80211\n\n/**************************************************************************\n * RSA declarations \n **************************************************************************/\n\ntypedef struct \n{\n    bigint *m;              /* modulus */\n    bigint *e;              /* public exponent */\n    bigint *d;              /* private exponent */\n#ifdef CONFIG_BIGINT_CRT\n    bigint *p;              /* p as in m = pq */\n    bigint *q;              /* q as in m = pq */\n    bigint *dP;             /* d mod (p-1) */\n    bigint *dQ;             /* d mod (q-1) */\n    bigint *qInv;           /* q^-1 mod p */\n#endif\n    int num_octets;\n    BI_CTX *bi_ctx;\n} RSA_CTX;\n\nvoid RSA_priv_key_new(RSA_CTX **rsa_ctx, \n        const uint8_t *modulus, int mod_len,\n        const uint8_t *pub_exp, int pub_len,\n        const uint8_t *priv_exp, int priv_len\n#ifdef CONFIG_BIGINT_CRT\n      , const uint8_t *p, int p_len,\n        const uint8_t *q, int q_len,\n        const uint8_t *dP, int dP_len,\n        const uint8_t *dQ, int dQ_len,\n        const uint8_t *qInv, int qInv_len\n#endif\n        );\nvoid RSA_pub_key_new(RSA_CTX **rsa_ctx, \n        const uint8_t *modulus, int mod_len,\n        const uint8_t *pub_exp, int pub_len);\nvoid RSA_free(RSA_CTX *ctx);\nint RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,\n        int is_decryption);\nbigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);\n#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)\nbigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,\n        bigint *modulus, bigint *pub_exp);\nbigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);\nint RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, \n        uint8_t *out_data, int is_signing);\nvoid RSA_print(const RSA_CTX *ctx);\n#endif\n\n/**************************************************************************\n * RNG declarations \n **************************************************************************/\nEXP_FUNC void STDCALL RNG_initialize(void);\nEXP_FUNC void STDCALL RNG_custom_init(const uint8_t *seed_buf, int size);\nEXP_FUNC void STDCALL RNG_terminate(void);\nEXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);\nvoid get_random_NZ(int num_rand_bytes, uint8_t *rand_data);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif \n"
  },
  {
    "path": "app/include/ssl/ssl_crypto_misc.h",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n/**\n * @file crypto_misc.h\n */\n\n#ifndef HEADER_CRYPTO_MISC_H\n#define HEADER_CRYPTO_MISC_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"ssl/ssl_crypto.h\"\n#include \"ssl/ssl_bigint.h\"\n\n/**************************************************************************\n * X509 declarations \n **************************************************************************/\n#define X509_OK                             0\n#define X509_NOT_OK                         -1\n#define X509_VFY_ERROR_NO_TRUSTED_CERT      -2\n#define X509_VFY_ERROR_BAD_SIGNATURE        -3      \n#define X509_VFY_ERROR_NOT_YET_VALID        -4\n#define X509_VFY_ERROR_EXPIRED              -5\n#define X509_VFY_ERROR_SELF_SIGNED          -6\n#define X509_VFY_ERROR_INVALID_CHAIN        -7\n#define X509_VFY_ERROR_UNSUPPORTED_DIGEST   -8\n#define X509_INVALID_PRIV_KEY               -9\n\n/*\n * The Distinguished Name\n */\n#define X509_NUM_DN_TYPES                   3\n#define X509_COMMON_NAME                    0\n#define X509_ORGANIZATION                   1\n#define X509_ORGANIZATIONAL_UNIT            2\n\nstruct _x509_ctx\n{\n    char *ca_cert_dn[X509_NUM_DN_TYPES];\n    char *cert_dn[X509_NUM_DN_TYPES];\n    char **subject_alt_dnsnames;\n    time_t not_before;\n    time_t not_after;\n    uint8_t *signature;\n    uint16_t sig_len;\n    uint8_t sig_type;\n    RSA_CTX *rsa_ctx;\n    bigint *digest;\n    struct _x509_ctx *next;\n};\n\ntypedef struct _x509_ctx X509_CTX;\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\ntypedef struct \n{\n    X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS];\n} CA_CERT_CTX;\n#endif\n\nint x509_new(const uint8_t *cert, int *len, X509_CTX **ctx);\nvoid x509_free(X509_CTX *x509_ctx);\n#ifdef CONFIG_SSL_CERT_VERIFICATION\nint x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert);\n#endif\n#ifdef CONFIG_SSL_FULL_MODE\nvoid x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx);\nconst char * x509_display_error(int error);\n#endif\n\n/**************************************************************************\n * ASN1 declarations \n **************************************************************************/\n#define ASN1_INTEGER            0x02\n#define ASN1_BIT_STRING         0x03\n#define ASN1_OCTET_STRING       0x04\n#define ASN1_NULL               0x05\n#define ASN1_PRINTABLE_STR2     0x0C\n#define ASN1_OID                0x06\n#define ASN1_PRINTABLE_STR2     0x0C\n#define ASN1_PRINTABLE_STR      0x13\n#define ASN1_TELETEX_STR        0x14\n#define ASN1_IA5_STR            0x16\n#define ASN1_UTC_TIME           0x17\n#define ASN1_UNICODE_STR        0x1e\n#define ASN1_SEQUENCE           0x30\n#define ASN1_CONTEXT_DNSNAME\t0x82\n#define ASN1_SET                0x31\n#define ASN1_V3_DATA\t\t\t0xa3\n#define ASN1_IMPLICIT_TAG       0x80\n#define ASN1_CONTEXT_DNSNAME\t0x82\n#define ASN1_EXPLICIT_TAG       0xa0\n#define ASN1_V3_DATA\t\t\t0xa3\n\n#define SIG_TYPE_MD2            0x02\n#define SIG_TYPE_MD5            0x04\n#define SIG_TYPE_SHA1           0x05\n\nint get_asn1_length(const uint8_t *buf, int *offset);\nint asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx);\nint asn1_next_obj(const uint8_t *buf, int *offset, int obj_type);\nint asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type);\nint asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object);\nint asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);\nint asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);\nint asn1_name(const uint8_t *cert, int *offset, char *dn[]);\nint asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);\n#ifdef CONFIG_SSL_CERT_VERIFICATION\nint asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx);\nint asn1_find_subjectaltname(const uint8_t* cert, int offset);\nint asn1_compare_dn(char * const dn1[], char * const dn2[]);\n#endif /* CONFIG_SSL_CERT_VERIFICATION */\nint asn1_signature_type(const uint8_t *cert, \n                                int *offset, X509_CTX *x509_ctx);\n\n/**************************************************************************\n * MISC declarations \n **************************************************************************/\n#define SALT_SIZE               8\n\nextern const char * const unsupported_str;\n\ntypedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int);\ntypedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, \n        int key_len, uint8_t *digest);\n\nint get_file(const char *filename, uint8_t **buf);\n\n#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG)\nEXP_FUNC void STDCALL print_blob(const char *format, const uint8_t *data, int size, ...);\n#else\n    #define print_blob(...)\n#endif\n\nEXP_FUNC int STDCALL base64_decode(const char *in,  int len,\n                    uint8_t *out, int *outlen);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif \n"
  },
  {
    "path": "app/include/ssl/ssl_os_int.h",
    "content": "/*\n * Copyright (c) 2012, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @file os_int.h\n *\n * Ensure a consistent bit size \n */\n\n#ifndef HEADER_OS_INT_H\n#define HEADER_OS_INT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(WIN32)\ntypedef UINT8 uint8_t;\ntypedef INT8 int8_t;\ntypedef UINT16 uint16_t;\ntypedef INT16 int16_t;\ntypedef UINT32 uint32_t;\ntypedef INT32 int32_t;\ntypedef UINT64 uint64_t;\ntypedef INT64 int64_t;\n#else   /* Not Win32 */\n\n#ifdef CONFIG_PLATFORM_SOLARIS\n#include <inttypes.h>\n#else\n//#include <stdint.h>\n#endif /* Not Solaris */\n\n#endif /* Not Win32 */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif \n"
  },
  {
    "path": "app/include/ssl/ssl_os_port.h",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @file os_port.h\n *\n * Some stuff to minimise the differences between windows and linux/unix\n */\n\n#ifndef HEADER_OS_PORT_H\n#define HEADER_OS_PORT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//#include \"../crypto/os_int.h\"\n#include \"c_types.h\"\n#include \"osapi.h\"\n#include <stdio.h>\n\n#if 0\n#define ssl_printf(fmt, args...) os_printf(fmt,## args)\n#else\n#define ssl_printf(fmt, args...)\n#endif\n\n#define STDCALL\n#define EXP_FUNC\n\nstruct timeval {\n  long    tv_sec;         /* seconds */\n  long    tv_usec;        /* and microseconds */\n};\n\n/* Mutexing definitions */\n\n#define SSL_CTX_MUTEX_INIT(A)\n#define SSL_CTX_MUTEX_DESTROY(A)\n#define SSL_CTX_LOCK(A)\n#define SSL_CTX_UNLOCK(A)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif \n"
  },
  {
    "path": "app/include/ssl/ssl_private_key.h",
    "content": "unsigned char default_private_key[] = {\n  0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xcd,\n  0xfd, 0x89, 0x48, 0xbe, 0x36, 0xb9, 0x95, 0x76, 0xd4, 0x13, 0x30, 0x0e,\n  0xbf, 0xb2, 0xed, 0x67, 0x0a, 0xc0, 0x16, 0x3f, 0x51, 0x09, 0x9d, 0x29,\n  0x2f, 0xb2, 0x6d, 0x3f, 0x3e, 0x6c, 0x2f, 0x90, 0x80, 0xa1, 0x71, 0xdf,\n  0xbe, 0x38, 0xc5, 0xcb, 0xa9, 0x9a, 0x40, 0x14, 0x90, 0x0a, 0xf9, 0xb7,\n  0x07, 0x0b, 0xe1, 0xda, 0xe7, 0x09, 0xbf, 0x0d, 0x57, 0x41, 0x86, 0x60,\n  0xa1, 0xc1, 0x27, 0x91, 0x5b, 0x0a, 0x98, 0x46, 0x1b, 0xf6, 0xa2, 0x84,\n  0xf8, 0x65, 0xc7, 0xce, 0x2d, 0x96, 0x17, 0xaa, 0x91, 0xf8, 0x61, 0x04,\n  0x50, 0x70, 0xeb, 0xb4, 0x43, 0xb7, 0xdc, 0x9a, 0xcc, 0x31, 0x01, 0x14,\n  0xd4, 0xcd, 0xcc, 0xc2, 0x37, 0x6d, 0x69, 0x82, 0xd6, 0xc6, 0xc4, 0xbe,\n  0xf2, 0x34, 0xa5, 0xc9, 0xa6, 0x19, 0x53, 0x32, 0x7a, 0x86, 0x0e, 0x91,\n  0x82, 0x0f, 0xa1, 0x42, 0x54, 0xaa, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01,\n  0x02, 0x81, 0x81, 0x00, 0x95, 0xaa, 0x6e, 0x11, 0xf5, 0x6a, 0x8b, 0xa2,\n  0xc6, 0x48, 0xc6, 0x7c, 0x37, 0x6b, 0x1f, 0x55, 0x10, 0x76, 0x26, 0x24,\n  0xc3, 0xf2, 0x5c, 0x5a, 0xdd, 0x2e, 0xf3, 0xa4, 0x1e, 0xbc, 0x7b, 0x1c,\n  0x80, 0x10, 0x85, 0xbc, 0xd8, 0x45, 0x3c, 0xb8, 0xb2, 0x06, 0x53, 0xb5,\n  0xd5, 0x7a, 0xe7, 0x0e, 0x92, 0xe6, 0x42, 0xc2, 0xe2, 0x2a, 0xd5, 0xd1,\n  0x03, 0x9f, 0x6f, 0x53, 0x74, 0x68, 0x72, 0x8e, 0xbf, 0x03, 0xbb, 0xab,\n  0xbd, 0xa1, 0xf9, 0x81, 0x7d, 0x12, 0xd4, 0x9d, 0xb6, 0xae, 0x4c, 0xad,\n  0xca, 0xa8, 0xc9, 0x80, 0x8d, 0x0d, 0xd5, 0xd0, 0xa1, 0xbf, 0xec, 0x60,\n  0x48, 0x49, 0xed, 0x97, 0x0f, 0x5e, 0xed, 0xfc, 0x39, 0x15, 0x96, 0x9e,\n  0x5d, 0xe2, 0xb4, 0x5d, 0x2e, 0x04, 0xdc, 0x08, 0xa2, 0x65, 0x29, 0x2d,\n  0x37, 0xfb, 0x62, 0x90, 0x1b, 0x7b, 0xe5, 0x3a, 0x58, 0x05, 0x55, 0xc1,\n  0x02, 0x41, 0x00, 0xfc, 0x69, 0x28, 0xc9, 0xa8, 0xc4, 0x5c, 0xe3, 0xd0,\n  0x5e, 0xaa, 0xda, 0xde, 0x87, 0x74, 0xdb, 0xcb, 0x40, 0x78, 0x8e, 0x1d,\n  0x12, 0x96, 0x16, 0x61, 0x3f, 0xb3, 0x3e, 0xa3, 0x0d, 0xdc, 0x49, 0xa5,\n  0x25, 0x87, 0xc5, 0x97, 0x85, 0x9d, 0xbb, 0xb4, 0xf0, 0x44, 0xfd, 0x6c,\n  0xe8, 0xd2, 0x8c, 0xec, 0x33, 0x81, 0x46, 0x1e, 0x10, 0x12, 0x33, 0x16,\n  0x95, 0x00, 0x4f, 0x75, 0xb4, 0xe5, 0x79, 0x02, 0x41, 0x00, 0xd0, 0xeb,\n  0x65, 0x07, 0x10, 0x3b, 0xd9, 0x03, 0xeb, 0xdc, 0x6f, 0x4b, 0x8f, 0xc3,\n  0x87, 0xce, 0x76, 0xd6, 0xc5, 0x14, 0x21, 0x4e, 0xe7, 0x4f, 0x1b, 0xe8,\n  0x05, 0xf8, 0x84, 0x1a, 0xe0, 0xc5, 0xd6, 0xe3, 0x08, 0xb3, 0x54, 0x57,\n  0x02, 0x1f, 0xd4, 0xd9, 0xfb, 0xff, 0x40, 0xb1, 0x56, 0x1c, 0x60, 0xf7,\n  0xac, 0x91, 0xf3, 0xd3, 0xc6, 0x7f, 0x84, 0xfd, 0x84, 0x9d, 0xea, 0x26,\n  0xee, 0xc9, 0x02, 0x41, 0x00, 0xa6, 0xcf, 0x1c, 0x6c, 0x81, 0x03, 0x1c,\n  0x5c, 0x56, 0x05, 0x6a, 0x26, 0x70, 0xef, 0xd6, 0x13, 0xb7, 0x74, 0x28,\n  0xf7, 0xca, 0x50, 0xd1, 0x2d, 0x83, 0x21, 0x64, 0xe4, 0xdd, 0x3f, 0x38,\n  0xb8, 0xd6, 0xd2, 0x41, 0xb3, 0x1c, 0x9a, 0xea, 0x0d, 0xf5, 0xda, 0xdf,\n  0xcd, 0x17, 0x9f, 0x9a, 0x1e, 0x15, 0xaf, 0x48, 0x1c, 0xbd, 0x9b, 0x63,\n  0x5b, 0xad, 0xed, 0xd4, 0xa1, 0xae, 0xa9, 0x59, 0x09, 0x02, 0x40, 0x4e,\n  0x08, 0xce, 0xa8, 0x8f, 0xc0, 0xba, 0xf3, 0x83, 0x02, 0xc8, 0x33, 0x62,\n  0x14, 0x77, 0xc2, 0x7f, 0x93, 0x02, 0xf3, 0xdc, 0xe9, 0x1a, 0xee, 0xea,\n  0x8e, 0x84, 0xc4, 0x69, 0x9b, 0x9c, 0x7f, 0x69, 0x1f, 0x4e, 0x1d, 0xa5,\n  0x90, 0x06, 0x44, 0x1b, 0x7d, 0xfc, 0x69, 0x40, 0x21, 0xbc, 0xf7, 0x46,\n  0xa4, 0xdc, 0x39, 0x7b, 0xe8, 0x8b, 0x49, 0x10, 0x44, 0x9d, 0x67, 0x5a,\n  0x91, 0x86, 0x39, 0x02, 0x40, 0x41, 0x2c, 0x4e, 0xfe, 0xd9, 0x90, 0x89,\n  0x00, 0x5c, 0x94, 0x0a, 0x4a, 0x7e, 0x1b, 0x1a, 0x80, 0x06, 0x01, 0x37,\n  0xda, 0x50, 0x61, 0x9d, 0x9c, 0xfe, 0x25, 0x7f, 0xd8, 0xd4, 0xc4, 0x9e,\n  0x81, 0xf2, 0x0c, 0x1e, 0x38, 0x21, 0x1e, 0x90, 0x3f, 0xd4, 0xba, 0x6c,\n  0x53, 0xcb, 0xf0, 0x77, 0x79, 0x9b, 0xf1, 0xfa, 0x3f, 0x81, 0xdc, 0xf3,\n  0x21, 0x02, 0x6d, 0xb7, 0x95, 0xc3, 0x2e, 0xce, 0xd5\n};\nunsigned int default_private_key_len = 609;\n"
  },
  {
    "path": "app/include/ssl/ssl_ssl.h",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @mainpage axTLS API\n *\n * @image html axolotl.jpg\n *\n * The axTLS library has features such as:\n * - The TLSv1 SSL client/server protocol\n * - No requirement to use any openssl libraries.\n * - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers.\n * - RSA encryption/decryption with variable sized keys (up to 4096 bits).\n * - Certificate chaining and peer authentication.\n * - Session resumption, session renegotiation.\n * - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding.\n * - Highly configurable compile time options.\n * - Portable across many platforms (written in ANSI C), and has language\n * bindings in C, C#, VB.NET, Java, Perl and Lua.\n * - Partial openssl API compatibility (via a wrapper).\n * - A very small footprint (around 50-60kB for the library in 'server-only' \n *   mode).\n * - No dependencies on sockets - can use serial connections for example.\n * - A very simple API - ~ 20 functions/methods.\n *\n * A list of these functions/methods are described below.\n *\n *  @ref c_api \n *\n *  @ref bigint_api \n *\n *  @ref csharp_api \n *\n *  @ref java_api \n */\n#ifndef HEADER_SSL_H\n#define HEADER_SSL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//#include <time.h>\ntypedef long     time_t;\n\n/* need to predefine before ssl_lib.h gets to it */\n#define SSL_SESSION_ID_SIZE                     32\n\n#include \"ssl/ssl_tls1.h\"\n\n/* The optional parameters that can be given to the client/server SSL engine */\n#define SSL_CLIENT_AUTHENTICATION               0x00010000\n#define SSL_SERVER_VERIFY_LATER                 0x00020000\n#define SSL_NO_DEFAULT_KEY                      0x00040000\n#define SSL_DISPLAY_STATES                      0x00080000\n#define SSL_DISPLAY_BYTES                       0x00100000\n#define SSL_DISPLAY_CERTS                       0x00200000\n#define SSL_DISPLAY_RSA                         0x00400000\n#define SSL_CONNECT_IN_PARTS                    0x00800000\n\n/* errors that can be generated */\n#define SSL_OK                                  0\n#define SSL_NOT_OK                              -1\n#define SSL_ERROR_DEAD                          -2\n#define SSL_CLOSE_NOTIFY                        -3\n#define SSL_ERROR_CONN_LOST                     -256\n#define SSL_ERROR_SOCK_SETUP_FAILURE            -258\n#define SSL_ERROR_INVALID_HANDSHAKE             -260\n#define SSL_ERROR_INVALID_PROT_MSG              -261\n#define SSL_ERROR_INVALID_HMAC                  -262\n#define SSL_ERROR_INVALID_VERSION               -263\n#define SSL_ERROR_INVALID_SESSION               -265\n#define SSL_ERROR_NO_CIPHER                     -266\n#define SSL_ERROR_BAD_CERTIFICATE               -268\n#define SSL_ERROR_INVALID_KEY                   -269\n#define SSL_ERROR_FINISHED_INVALID              -271\n#define SSL_ERROR_NO_CERT_DEFINED               -272\n#define SSL_ERROR_NO_CLIENT_RENOG               -273\n#define SSL_ERROR_NOT_SUPPORTED                 -274\n#define SSL_X509_OFFSET                         -512\n#define SSL_X509_ERROR(A)                       (SSL_X509_OFFSET+A)\n\n/* alert types that are recognized */\n#define SSL_ALERT_TYPE_WARNING                  1\n#define SLL_ALERT_TYPE_FATAL                    2\n\n/* these are all the alerts that are recognized */\n#define SSL_ALERT_CLOSE_NOTIFY                  0\n#define SSL_ALERT_UNEXPECTED_MESSAGE            10\n#define SSL_ALERT_BAD_RECORD_MAC                20\n#define SSL_ALERT_HANDSHAKE_FAILURE             40\n#define SSL_ALERT_BAD_CERTIFICATE               42\n#define SSL_ALERT_ILLEGAL_PARAMETER             47\n#define SSL_ALERT_DECODE_ERROR                  50\n#define SSL_ALERT_DECRYPT_ERROR                 51\n#define SSL_ALERT_INVALID_VERSION               70\n#define SSL_ALERT_NO_RENEGOTIATION              100\n\n/* The ciphers that are supported */\n#define SSL_AES128_SHA                          0x2f\n#define SSL_AES256_SHA                          0x35\n#define SSL_RC4_128_SHA                         0x05\n#define SSL_RC4_128_MD5                         0x04\n\n/* build mode ids' */\n#define SSL_BUILD_SKELETON_MODE                 0x01\n#define SSL_BUILD_SERVER_ONLY                   0x02\n#define SSL_BUILD_ENABLE_VERIFICATION           0x03\n#define SSL_BUILD_ENABLE_CLIENT                 0x04\n#define SSL_BUILD_FULL_MODE                     0x05\n\n/* offsets to retrieve configuration information */\n#define SSL_BUILD_MODE                          0\n#define SSL_MAX_CERT_CFG_OFFSET                 1\n#define SSL_MAX_CA_CERT_CFG_OFFSET              2\n#define SSL_HAS_PEM                             3\n\n/* default session sizes */\n#define SSL_DEFAULT_SVR_SESS                    1\t//modify 5->1 by lhan\n#define SSL_DEFAULT_CLNT_SESS                   1\n\n/* X.509/X.520 distinguished name types */\n#define SSL_X509_CERT_COMMON_NAME               0\n#define SSL_X509_CERT_ORGANIZATION              1\n#define SSL_X509_CERT_ORGANIZATIONAL_NAME       2\n#define SSL_X509_CA_CERT_COMMON_NAME            3\n#define SSL_X509_CA_CERT_ORGANIZATION           4\n#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME    5\n\n/* SSL object loader types */\n#define SSL_OBJ_X509_CERT                       1\n#define SSL_OBJ_X509_CACERT                     2\n#define SSL_OBJ_RSA_KEY                         3\n#define SSL_OBJ_PKCS8                           4\n#define SSL_OBJ_PKCS12                          5\n\n/**\n * @defgroup c_api Standard C API\n * @brief The standard interface in C.\n * @{\n */\n\n/**\n * @brief Establish a new client/server context.\n *\n * This function is called before any client/server SSL connections are made. \n *\n * Each new connection will use the this context's private key and \n * certificate chain. If a different certificate chain is required, then a \n * different context needs to be be used.\n *\n * There are two threading models supported - a single thread with one\n * SSL_CTX can support any number of SSL connections - and multiple threads can \n * support one SSL_CTX object each (the default). But if a single SSL_CTX \n * object uses many SSL objects in individual threads, then the \n * CONFIG_SSL_CTX_MUTEXING option needs to be configured.\n *\n * @param options [in]  Any particular options. At present the options\n * supported are:\n * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server\n * authentication fails. The certificate can be authenticated later with a\n * call to ssl_verify_cert().\n * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication\n * i.e. each handshake will include a \"certificate request\" message from the\n * server. Only available if verification has been enabled.\n * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences\n * during the handshake.\n * - SSL_DISPLAY_STATES (full mode build only): Display the state changes\n * during the handshake.\n * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that\n * are passed during a handshake.\n * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that\n * are passed during a handshake.\n * - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of \n * ssl_client_new().\n * @param num_sessions [in] The number of sessions to be used for session\n * caching. If this value is 0, then there is no session caching. This option\n * is not used in skeleton mode.\n * @return A client/server context.\n */\nEXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions);\n\n/**\n * @brief Remove a client/server context.\n *\n * Frees any used resources used by this context. Each connection will be \n * sent a \"Close Notify\" alert (if possible).\n * @param ssl_ctx [in] The client/server context.\n */\nEXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx);\n\n/**\n * @brief (server only) Establish a new SSL connection to an SSL client.\n *\n * It is up to the application to establish the logical connection (whether it\n * is  a socket, serial connection etc).\n * @param ssl_ctx [in] The server context.\n * @param client_fd [in] The client's file descriptor. \n * @return An SSL object reference.\n */\n//EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd);\n\nEXP_FUNC SSL *STDCALL sslserver_new(SSL_CTX *ssl_ctx, struct tcp_pcb* client_pcb);\n/**\n * @brief (client only) Establish a new SSL connection to an SSL server.\n *\n * It is up to the application to establish the initial logical connection \n * (whether it is  a socket, serial connection etc).\n *\n * This is a normally a blocking call - it will finish when the handshake is \n * complete (or has failed). To use in non-blocking mode, set \n * SSL_CONNECT_IN_PARTS in ssl_ctx_new().\n * @param ssl_ctx [in] The client context.\n * @param client_fd [in] The client's file descriptor.\n * @param session_id [in] A 32 byte session id for session resumption. This \n * can be null if no session resumption is being used or required. This option\n * is not used in skeleton mode.\n * @param sess_id_size The size of the session id (max 32)\n * @return An SSL object reference. Use ssl_handshake_status() to check \n * if a handshake succeeded.\n */\n//EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size);\n\nEXP_FUNC SSL *STDCALL SSLClient_new(SSL_CTX *ssl_ctx, struct tcp_pcb *SslClient_pcb, const\n                                        uint8_t *session_id, uint8_t sess_id_size);\n/**\n * @brief Free any used resources on this connection. \n \n * A \"Close Notify\" message is sent on this connection (if possible). It is up \n * to the application to close the socket or file descriptor.\n * @param ssl [in] The ssl object reference.\n */\nEXP_FUNC void STDCALL ssl_free(SSL *ssl);\n\n/**\n * @brief Read the SSL data stream.\n * If the socket is non-blocking and data is blocked then SSO_OK will be\n * returned.\n * @param ssl [in] An SSL object reference.\n * @param in_data [out] If the read was successful, a pointer to the read\n * buffer will be here. Do NOT ever free this memory as this buffer is used in\n * sucessive calls. If the call was unsuccessful, this value will be null.\n * @return The number of decrypted bytes:\n * - if > 0, then the handshaking is complete and we are returning the number \n *   of decrypted bytes. \n * - SSL_OK if the handshaking stage is successful (but not yet complete).  \n * - < 0 if an error.\n * @see ssl.h for the error code list.\n * @note Use in_data before doing any successive ssl calls.\n */\nEXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data);\n\n/**\n * @brief Write to the SSL data stream. \n * if the socket is non-blocking and data is blocked then a check is made\n * to ensure that all data is sent (i.e. blocked mode is forced).\n * @param ssl [in] An SSL obect reference.\n * @param out_data [in] The data to be written\n * @param out_len [in] The number of bytes to be written.\n * @return The number of bytes sent, or if < 0 if an error.\n * @see ssl.h for the error code list.\n */\nEXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len);\n\n/**\n * @brief Find an ssl object based on a file descriptor.\n *\n * Goes through the list of SSL objects maintained in a client/server context\n * to look for a file descriptor match.\n * @param ssl_ctx [in] The client/server context.\n * @param client_fd [in]  The file descriptor.\n * @return A reference to the SSL object. Returns null if the object could not \n * be found.\n */\nEXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd);\n\n/**\n * @brief Get the session id for a handshake. \n * \n * This will be a 32 byte sequence and is available after the first\n * handshaking messages are sent.\n * @param ssl [in] An SSL object reference.\n * @return The session id as a 32 byte sequence.\n * @note A SSLv23 handshake may have only 16 valid bytes.\n */\nEXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl);\n\n/**\n * @brief Get the session id size for a handshake. \n * \n * This will normally be 32 but could be 0 (no session id) or something else.\n * @param ssl [in] An SSL object reference.\n * @return The size of the session id.\n */\nEXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl);\n\n/**\n * @brief Return the cipher id (in the SSL form).\n * @param ssl [in] An SSL object reference.\n * @return The cipher id. This will be one of the following:\n * - SSL_AES128_SHA (0x2f)\n * - SSL_AES256_SHA (0x35)\n * - SSL_RC4_128_SHA (0x05)\n * - SSL_RC4_128_MD5 (0x04)\n */\nEXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl);\n\n/**\n * @brief Return the status of the handshake.\n * @param ssl [in] An SSL object reference.\n * @return SSL_OK if the handshake is complete and ok. \n * @see ssl.h for the error code list.\n */\nEXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl);\n\n/**\n * @brief Retrieve various parameters about the axTLS engine.\n * @param offset [in] The configuration offset. It will be one of the following:\n * - SSL_BUILD_MODE The build mode. This will be one of the following:\n *   - SSL_BUILD_SERVER_ONLY            (basic server mode)\n *   - SSL_BUILD_ENABLE_VERIFICATION    (server can do client authentication)\n *   - SSL_BUILD_ENABLE_CLIENT          (client/server capabilties)\n *   - SSL_BUILD_FULL_MODE              (client/server with diagnostics)\n *   - SSL_BUILD_SKELETON_MODE          (skeleton mode)\n * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed.\n * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed.\n * - SSL_HAS_PEM                        1 if supported\n * @return The value of the requested parameter.\n */\nEXP_FUNC int STDCALL ssl_get_config(int offset);\n\n/**\n * @brief Display why the handshake failed.\n *\n * This call is only useful in a 'full mode' build. The output is to stdout.\n * @param error_code [in] An error code.\n * @see ssl.h for the error code list.\n */\n//EXP_FUNC void STDCALL ssl_display_error(int error_code);\n\n/**\n * @brief Authenticate a received certificate.\n * \n * This call is usually made by a client after a handshake is complete and the\n * context is in SSL_SERVER_VERIFY_LATER mode.\n * @param ssl [in] An SSL object reference.\n * @return SSL_OK if the certificate is verified.\n */\nEXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl);\n\n/**\n * @brief Retrieve an X.509 distinguished name component.\n * \n * When a handshake is complete and a certificate has been exchanged, then the\n * details of the remote certificate can be retrieved.\n *\n * This will usually be used by a client to check that the server's common \n * name matches the URL.\n *\n * @param ssl [in] An SSL object reference.\n * @param component [in] one of:\n * - SSL_X509_CERT_COMMON_NAME\n * - SSL_X509_CERT_ORGANIZATION\n * - SSL_X509_CERT_ORGANIZATIONAL_NAME\n * - SSL_X509_CA_CERT_COMMON_NAME\n * - SSL_X509_CA_CERT_ORGANIZATION\n * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME\n * @return The appropriate string (or null if not defined)\n * @note Verification build mode must be enabled.\n */\nEXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component);\n\n/**\n * @brief Retrieve a Subject Alternative DNSName\n *\n * When a handshake is complete and a certificate has been exchanged, then the\n * details of the remote certificate can be retrieved.\n *\n * This will usually be used by a client to check that the server's DNS  \n * name matches the URL.\n *\n * @param ssl [in] An SSL object reference.\n * @param dnsindex [in] The index of the DNS name to retrieve.\n * @return The appropriate string (or null if not defined)\n * @note Verification build mode must be enabled.\n */\nEXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex);\n\n/**\n * @brief Force the client to perform its handshake again.\n *\n * For a client this involves sending another \"client hello\" message.\n * For the server is means sending a \"hello request\" message.\n *\n * This is a blocking call on the client (until the handshake completes).\n *\n * @param ssl [in] An SSL object reference.\n * @return SSL_OK if renegotiation instantiation was ok\n */\nEXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl);\n\n/**\n * @brief Process a file that is in binary DER or ASCII PEM format.\n *\n * These are temporary objects that are used to load private keys,\n * certificates etc into memory.\n * @param ssl_ctx [in] The client/server context.\n * @param obj_type [in] The format of the file. Can be one of:\n * - SSL_OBJ_X509_CERT (no password required)\n * - SSL_OBJ_X509_CACERT (no password required)\n * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)\n * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported)\n * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported)\n *\n * PEM files are automatically detected (if supported). The object type is\n * also detected, and so is not relevant for these types of files.\n * @param filename [in] The location of a file in DER/PEM format.\n * @param password [in] The password used. Can be null if not required.\n * @return SSL_OK if all ok\n * @note Not available in skeleton build mode.\n */\nEXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password);\n\n/**\n * @brief Process binary data.\n *\n * These are temporary objects that are used to load private keys,\n * certificates etc into memory.\n * @param ssl_ctx [in] The client/server context.\n * @param obj_type [in] The format of the memory data.\n * @param data [in] The binary data to be loaded.\n * @param len [in] The amount of data to be loaded.\n * @param password [in] The password used. Can be null if not required.\n * @return SSL_OK if all ok\n * @see ssl_obj_load for more details on obj_type.\n */\nEXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password);\n\n#ifdef CONFIG_SSL_GENERATE_X509_CERT\n/**\n * @brief Create an X.509 certificate. \n * \n * This certificate is a self-signed v1 cert with a fixed start/stop validity \n * times. It is signed with an internal private key in ssl_ctx.\n *\n * @param ssl_ctx [in] The client/server context.\n * @param options [in] Not used yet.\n * @param dn [in] An array of distinguished name strings. The array is defined\n * by:\n * - SSL_X509_CERT_COMMON_NAME (0)\n *      - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the \n *        hostname will be used.\n * - SSL_X509_CERT_ORGANIZATION (1)\n *      - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME \n *        will be used.\n * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2)\n *      - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional.\n * @param cert_data [out] The certificate as a sequence of bytes.\n * @return < 0 if an error, or the size of the certificate in bytes.\n * @note cert_data must be freed when there is no more need for it.\n */\nEXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data);\n#endif\n\n/**\n * @brief Return the axTLS library version as a string.\n */\nEXP_FUNC const char * STDCALL ssl_version(void);\n\n/** @} */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "app/include/ssl/ssl_tls1.h",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @file tls1.h\n *\n * @brief The definitions for the TLS library.\n */\n#ifndef HEADER_SSL_LIB_H\n#define HEADER_SSL_LIB_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"c_types.h\"\n#include \"ssl/ssl_version.h\"\n#include \"ssl/ssl_config.h\"\n//#include \"../crypto/os_int.h\"\n#include \"ssl/ssl_crypto.h\"\n#include \"ssl/ssl_crypto_misc.h\"\n#include \"lwip/tcp.h\"\n\n#define SSL_PROTOCOL_MIN_VERSION    0x31   /* TLS v1.0 */\n#define SSL_PROTOCOL_MINOR_VERSION  0x02   /* TLS v1.1 */\n#define SSL_PROTOCOL_VERSION_MAX    0x32   /* TLS v1.1 */\n#define SSL_PROTOCOL_VERSION1_1     0x32   /* TLS v1.1 */\n#define SSL_RANDOM_SIZE             32\n#define SSL_SECRET_SIZE             48\n#define SSL_FINISHED_HASH_SIZE      12\n#define SSL_RECORD_SIZE             5\n#define SSL_SERVER_READ             0\n#define SSL_SERVER_WRITE            1\n#define SSL_CLIENT_READ             2\n#define SSL_CLIENT_WRITE            3\n#define SSL_HS_HDR_SIZE             4\n\n/* the flags we use while establishing a connection */\n#define SSL_NEED_RECORD             0x0001\n#define SSL_TX_ENCRYPTED            0x0002 \n#define SSL_RX_ENCRYPTED            0x0004\n#define SSL_SESSION_RESUME          0x0008\n#define SSL_IS_CLIENT               0x0010\n#define SSL_HAS_CERT_REQ            0x0020\n#define SSL_SENT_CLOSE_NOTIFY       0x0040\n\n/* some macros to muck around with flag bits */\n#define SET_SSL_FLAG(A)             (ssl->flag |= A)\n#define CLR_SSL_FLAG(A)             (ssl->flag &= ~A)\n#define IS_SET_SSL_FLAG(A)          (ssl->flag & A)\n\n#define MAX_KEY_BYTE_SIZE           512     /* for a 4096 bit key */\n#define RT_MAX_PLAIN_LENGTH         4096\n#define RT_EXTRA                    1024\n#define BM_RECORD_OFFSET            5\n\n#ifdef CONFIG_SSL_SKELETON_MODE\n#define NUM_PROTOCOLS               1\n#else\n#define NUM_PROTOCOLS               4\n#endif\n\n#define PARANOIA_CHECK(A, B)        if (A < B) { \\\n    ret = SSL_ERROR_INVALID_HANDSHAKE; goto error; }\n\n/* protocol types */\nenum\n{\n    PT_CHANGE_CIPHER_SPEC = 20,\n    PT_ALERT_PROTOCOL,\n    PT_HANDSHAKE_PROTOCOL,\n    PT_APP_PROTOCOL_DATA\n};\n\n/* handshaking types */\nenum\n{\n    HS_HELLO_REQUEST,\n    HS_CLIENT_HELLO,\n    HS_SERVER_HELLO,\n    HS_CERTIFICATE = 11,\n    HS_SERVER_KEY_XCHG,\n    HS_CERT_REQ,\n    HS_SERVER_HELLO_DONE,\n    HS_CERT_VERIFY,\n    HS_CLIENT_KEY_XCHG,\n    HS_FINISHED = 20\n};\n\ntypedef struct \n{\n    uint8_t cipher;\n    uint8_t key_size;\n    uint8_t iv_size;\n    uint8_t key_block_size;\n    uint8_t padding_size;\n    uint8_t digest_size;\n    hmac_func hmac;\n    crypt_func encrypt;\n    crypt_func decrypt;\n} cipher_info_t;\n\nstruct _SSLObjLoader \n{\n    uint8_t *buf;\n    int len;\n};\n\ntypedef struct _SSLObjLoader SSLObjLoader;\n\ntypedef struct \n{\n    time_t conn_time;\n    uint8_t session_id[SSL_SESSION_ID_SIZE];\n    uint8_t master_secret[SSL_SECRET_SIZE];\n} SSL_SESSION;\n\ntypedef struct\n{\n    uint8_t *buf;\n    int size;\n} SSL_CERT;\n\ntypedef struct\n{\n    MD5_CTX md5_ctx;\n    SHA1_CTX sha1_ctx;\n    uint8_t final_finish_mac[SSL_FINISHED_HASH_SIZE];\n    uint8_t *key_block;\n    uint8_t master_secret[SSL_SECRET_SIZE];\n    uint8_t client_random[SSL_RANDOM_SIZE]; /* client's random sequence */\n    uint8_t server_random[SSL_RANDOM_SIZE]; /* server's random sequence */\n    uint16_t bm_proc_index;\n} DISPOSABLE_CTX;\n\nstruct _SSL\n{\n    uint32_t flag;\n    uint16_t need_bytes;\n    uint16_t got_bytes;\n    uint8_t record_type;\n    uint8_t cipher;\n    uint8_t sess_id_size;\n    uint8_t version;\n    uint8_t client_version;\n    sint16_t next_state;\n    sint16_t hs_status;\n    DISPOSABLE_CTX *dc;         /* temporary data which we'll get rid of soon */\n    //int client_fd;\n\tstruct tcp_pcb *SslClient_pcb;//add by ives 12.12.2013\n    struct pbuf *ssl_pbuf;//add by ives 12.12.2013\n    const cipher_info_t *cipher_info;\n    void *encrypt_ctx;\n    void *decrypt_ctx;\n    uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH+RT_EXTRA];\n    uint8_t *bm_data;\n    uint16_t bm_index;\n    uint16_t bm_read_index;\n    struct _SSL *next;                  /* doubly linked list */\n    struct _SSL *prev;\n    struct _SSL_CTX *ssl_ctx;           /* back reference to a clnt/svr ctx */\n#ifndef CONFIG_SSL_SKELETON_MODE\n    uint16_t session_index;\n    SSL_SESSION *session;\n#endif\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n    X509_CTX *x509_ctx;\n#endif\n\n    uint8_t session_id[SSL_SESSION_ID_SIZE]; \n    uint8_t client_mac[SHA1_SIZE];  /* for HMAC verification */\n    uint8_t server_mac[SHA1_SIZE];  /* for HMAC verification */\n    uint8_t read_sequence[8];       /* 64 bit sequence number */\n    uint8_t write_sequence[8];      /* 64 bit sequence number */\n    uint8_t hmac_header[SSL_RECORD_SIZE];    /* rx hmac */\n};\n\ntypedef struct _SSL SSL;\n\nstruct _SSL_CTX\n{\n    uint32_t options;\n    uint8_t chain_length;\n    RSA_CTX *rsa_ctx;\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n    CA_CERT_CTX *ca_cert_ctx;\n#endif\n    SSL *head;\n    SSL *tail;\n    SSL_CERT certs[CONFIG_SSL_MAX_CERTS];\n#ifndef CONFIG_SSL_SKELETON_MODE\n    uint16_t num_sessions;\n    SSL_SESSION **ssl_sessions;\n#endif\n#ifdef CONFIG_SSL_CTX_MUTEXING\n    SSL_CTX_MUTEX_TYPE mutex;\n#endif\n#ifdef CONFIG_OPENSSL_COMPATIBLE\n    void *bonus_attr;\n#endif\n};\n\ntypedef struct _SSL_CTX SSL_CTX;\n\n/* backwards compatibility */\ntypedef struct _SSL_CTX SSLCTX;\n\nextern const uint8_t ssl_prot_prefs[NUM_PROTOCOLS];\n\nSSL *ssl_new(SSL_CTX *ssl_ctx, int client_fd);\nSSL *ssl_new_context(SSL_CTX *ssl_ctx, struct tcp_pcb *SslClient_pcb);\nvoid disposable_new(SSL *ssl);\nvoid disposable_free(SSL *ssl);\nint send_packet(SSL *ssl, uint8_t protocol, \n        const uint8_t *in, int length);\nint do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);\nint do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len);\nint process_finished(SSL *ssl, uint8_t *buf, int hs_len);\nint process_sslv23_client_hello(SSL *ssl);\nint send_alert(SSL *ssl, int error_code);\nint send_finished(SSL *ssl);\nint send_certificate(SSL *ssl);\nint basic_read(SSL *ssl, uint8_t **in_data);\nint send_change_cipher_spec(SSL *ssl);\nvoid finished_digest(SSL *ssl, const char *label, uint8_t *digest);\nvoid generate_master_secret(SSL *ssl, const uint8_t *premaster_secret);\nvoid add_packet(SSL *ssl, const uint8_t *pkt, int len);\nint add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);\nint add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj);\nvoid ssl_obj_free(SSLObjLoader *ssl_obj);\nint pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);\nint pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password);\nint load_key_certs(SSL_CTX *ssl_ctx);\n#ifdef CONFIG_SSL_CERT_VERIFICATION\nint add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len);\nvoid remove_ca_certs(CA_CERT_CTX *ca_cert_ctx);\n#endif\n#ifdef CONFIG_SSL_ENABLE_CLIENT\nint do_client_connect(SSL *ssl);\n#endif\n\n#ifdef CONFIG_SSL_FULL_MODE\n//void DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok);\n//void DISPLAY_BYTES(SSL *ssl, const char *format,\n//        const uint8_t *data, int size, ...);\n//void DISPLAY_CERT(SSL *ssl, const X509_CTX *x509_ctx);\n//void DISPLAY_RSA(SSL *ssl,  const RSA_CTX *rsa_ctx);\n//void DISPLAY_ALERT(SSL *ssl, int alert);\n#else\n#define DISPLAY_STATE(A,B,C,D)\n#define DISPLAY_CERT(A,B)\n#define DISPLAY_RSA(A,B)\n#define DISPLAY_ALERT(A, B)\n#ifdef WIN32\nvoid DISPLAY_BYTES(SSL *ssl, const char *format,/* win32 has no variadic macros */\n        const uint8_t *data, int size, ...);\n#else\n#define DISPLAY_BYTES(A,B,C,D,...)\n#endif\n#endif\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\nint process_certificate(SSL *ssl, X509_CTX **x509_ctx);\n#endif\n\nSSL_SESSION *ssl_session_update(int max_sessions, \n        SSL_SESSION *ssl_sessions[], SSL *ssl,\n        const uint8_t *session_id);\nvoid kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif \n"
  },
  {
    "path": "app/include/ssl/ssl_version.h",
    "content": "#define AXTLS_VERSION    \"1.4.9\"\n"
  },
  {
    "path": "app/include/user_config.h",
    "content": "#ifndef __USER_CONFIG_H__\n#define __USER_CONFIG_H__\n\n\n#define INTERFACE_DOMAIN \"smart.relay.com\"\n\n\n#define FLASH_512K\n// #define FLASH_1M\n// #define FLASH_2M\n// #define FLASH_4M\n//#define FLASH_AUTOSIZE\n#define DEVELOP_VERSION\n//#define FULL_VERSION_FOR_USER\n\n#define USE_OPTIMIZE_PRINTF\n\n#ifdef DEVELOP_VERSION\n#define NODE_DEBUG\n#endif\t/* DEVELOP_VERSION */\n\n#define DEBUG_UART 0 //debug on uart 0 or 1\n\n//#define NODE_ERROR\n\n#ifdef NODE_DEBUG\n#define NODE_DBG(...) os_printf(\"\\r\\n\");os_printf( __VA_ARGS__ )\n#else\n#define NODE_DBG\n#endif\t/* NODE_DEBUG */\n\n#ifdef NODE_ERROR\n#define NODE_ERR c_printf\n#else\n#define NODE_ERR\n#endif\t/* NODE_ERROR */\n\n#define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed))\n#define ICACHE_STORE_ATTR __attribute__((aligned(4)))\n#define ICACHE_RAM_ATTR __attribute__((section(\".iram0.text\")))\n// #define ICACHE_RODATA_ATTR __attribute__((section(\".rodata2.text\")))\n\n\n#define GPIO_INTERRUPT_ENABLE\n\n//#define BUILD_WOFS\t\t1\n#define BUILD_SPIFFS\t1\n\n#define PRINTF_LONG_SUPPORT\n\n\n\n#endif\t/* __USER_CONFIG_H__ */\n"
  },
  {
    "path": "app/include/xtensa/cacheasm.h",
    "content": "/*\r\n * xtensa/cacheasm.h -- assembler-specific cache related definitions\r\n *\t\t\tthat depend on CORE configuration\r\n *\r\n *  This file is logically part of xtensa/coreasm.h ,\r\n *  but is kept separate for modularity / compilation-performance.\r\n */\r\n\r\n/*\r\n * Copyright (c) 2001-2002, 2006 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef XTENSA_CACHEASM_H\r\n#define XTENSA_CACHEASM_H\r\n\r\n#include <xtensa/coreasm.h>\r\n#include <xtensa/xtensa-xer.h>\r\n\r\n/*\r\n *  This header file defines assembler macros of the form:\r\n *\t<x>cache_<func>\r\n *  where <x> is 'i' or 'd' for instruction and data caches,\r\n *  and <func> indicates the function of the macro.\r\n *\r\n *  The following functions <func> are defined,\r\n *  and apply only to the specified cache (I or D):\r\n *\r\n *  reset\r\n *\tResets the cache.\r\n *\r\n *  sync\r\n *\tMakes sure any previous cache instructions have been completed;\r\n *\tie. makes sure any previous cache control operations\r\n *\thave had full effect and been synchronized to memory.\r\n *\tEg. any invalidate completed [so as not to generate a hit],\r\n *\tany writebacks or other pipelined writes written to memory, etc.\r\n *\r\n *  invalidate_line\t\t(single cache line)\r\n *  invalidate_region\t\t(specified memory range)\r\n *  invalidate_all\t\t(entire cache)\r\n *\tInvalidates all cache entries that cache\r\n *\tdata from the specified memory range.\r\n *\tNOTE: locked entries are not invalidated.\r\n *\r\n *  writeback_line\t\t(single cache line)\r\n *  writeback_region\t\t(specified memory range)\r\n *  writeback_all\t\t(entire cache)\r\n *\tWrites back to memory all dirty cache entries\r\n *\tthat cache data from the specified memory range,\r\n *\tand marks these entries as clean.\r\n *\tNOTE: on some future implementations, this might\r\n *\t\talso invalidate.\r\n *\tNOTE: locked entries are written back, but never invalidated.\r\n *\tNOTE: instruction caches never implement writeback.\r\n *\r\n *  writeback_inv_line\t\t(single cache line)\r\n *  writeback_inv_region\t(specified memory range)\r\n *  writeback_inv_all\t\t(entire cache)\r\n *\tWrites back to memory all dirty cache entries\r\n *\tthat cache data from the specified memory range,\r\n *\tand invalidates these entries (including all clean\r\n *\tcache entries that cache data from that range).\r\n *\tNOTE: locked entries are written back but not invalidated.\r\n *\tNOTE: instruction caches never implement writeback.\r\n *\r\n *  lock_line\t\t\t(single cache line)\r\n *  lock_region\t\t\t(specified memory range)\r\n *\tPrefetch and lock the specified memory range into cache.\r\n *\tNOTE:  if any part of the specified memory range cannot\r\n *\tbe locked, a Load/Store Error (for dcache) or Instruction\r\n *\tFetch Error (for icache) exception occurs.  These macros don't\r\n *\tdo anything special (yet anyway) to handle this situation.\r\n *\r\n *  unlock_line\t\t\t(single cache line)\r\n *  unlock_region\t\t(specified memory range)\r\n *  unlock_all\t\t\t(entire cache)\r\n *\tUnlock cache entries that cache the specified memory range.\r\n *\tEntries not already locked are unaffected.\r\n *\r\n *  coherence_on\r\n *  coherence_off\r\n *      Turn off and on cache coherence\r\n *\r\n */\r\n\r\n\r\n\r\n/***************************   GENERIC -- ALL CACHES   ***************************/\r\n\r\n\r\n/*\r\n *  The following macros assume the following cache size/parameter limits\r\n *  in the current Xtensa core implementation:\r\n *\tcache size:\t1024 bytes minimum\r\n *\tline size:\t16 - 64 bytes\r\n *\tway count:\t1 - 4\r\n *\r\n *  Minimum entries per way (ie. per associativity) = 1024 / 64 / 4 = 4\r\n *  Hence the assumption that each loop can execute four cache instructions.\r\n *\r\n *  Correspondingly, the offset range of instructions is assumed able to cover\r\n *  four lines, ie. offsets {0,1,2,3} * line_size are assumed valid for\r\n *  both hit and indexed cache instructions.  Ie. these offsets are all\r\n *  valid:  0, 16, 32, 48, 64, 96, 128, 192 (for line sizes 16, 32, 64).\r\n *  This is true of all original cache instructions\r\n *  (dhi, ihi, dhwb, dhwbi, dii, iii) which have offsets\r\n *  of 0 to 1020 in multiples of 4 (ie. 8 bits shifted by 2).\r\n *  This is also true of subsequent cache instructions\r\n *  (dhu, ihu, diu, iiu, diwb, diwbi, dpfl, ipfl) which have offsets\r\n *  of 0 to 240 in multiples of 16 (ie. 4 bits shifted by 4).\r\n *\r\n *  (Maximum cache size, currently 32k, doesn't affect the following macros.\r\n *  Cache ways > MMU min page size cause aliasing but that's another matter.)\r\n */\r\n\r\n\r\n\r\n/*\r\n *  Macro to apply an 'indexed' cache instruction to the entire cache.\r\n *\r\n *  Parameters:\r\n *\tcainst\t\tinstruction/ that takes an address register parameter\r\n *\t\t\tand an offset parameter (in range 0 .. 3*linesize).\r\n *\tsize\t\tsize of cache in bytes\r\n *\tlinesize\tsize of cache line in bytes (always power-of-2)\r\n *\tassoc_or1\tnumber of associativities (ways/sets) in cache\r\n *\t\t\tif all sets affected by cainst,\r\n *\t\t\tor 1 if only one set (or not all sets) of the cache\r\n *\t\t\tis affected by cainst (eg. DIWB or DIWBI [not yet ISA defined]).\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n *\tloopokay\t1 (default) allows use of zero-overhead loops, 0 does not\r\n *\timmrange\trange (max value) of cainst's immediate offset parameter, in bytes\r\n *\t\t\t(NOTE: macro assumes immrange allows power-of-2 number of lines)\r\n */\r\n\r\n\t.macro\tcache_index_all\t\tcainst, size, linesize, assoc_or1, aa, ab, loopokay=1, maxofs=240\r\n\r\n\t//  Number of indices in cache (lines per way):\r\n\t.set\t.Lindices, (\\size / (\\linesize * \\assoc_or1))\r\n\t//  Number of indices processed per loop iteration (max 4):\r\n\t.set\t.Lperloop, .Lindices\r\n\t.ifgt\t.Lperloop - 4\r\n\t .set\t.Lperloop, 4\r\n\t.endif\r\n\t//  Also limit instructions per loop if cache line size exceeds immediate range:\r\n\t.set\t.Lmaxperloop, (\\maxofs / \\linesize) + 1\r\n\t.ifgt\t.Lperloop - .Lmaxperloop\r\n\t .set\t.Lperloop, .Lmaxperloop\r\n\t.endif\r\n\t//  Avoid addi of 128 which takes two instructions (addmi,addi):\r\n\t.ifeq\t.Lperloop*\\linesize - 128\r\n\t .ifgt\t.Lperloop - 1\r\n\t  .set\t.Lperloop, .Lperloop / 2\r\n\t .endif\r\n\t.endif\r\n\r\n\t//  \\size byte cache, \\linesize byte lines, \\assoc_or1 way(s) affected by each \\cainst.\r\n\t.ifne\t(\\loopokay & XCHAL_HAVE_LOOPS)\r\n\r\n\tmovi\t\\aa, .Lindices / .Lperloop\t\t// number of loop iterations\r\n\t// Possible improvement: need only loop if \\aa > 1 ;\r\n\t// however \\aa == 1 is highly unlikely.\r\n\tmovi\t\\ab, 0\t\t// to iterate over cache\r\n\tloop\t\t\\aa, .Lend_cachex\\@\r\n\t.set\t.Li, 0 ;     .rept .Lperloop\r\n\t  \\cainst\t\\ab, .Li*\\linesize\r\n\t.set\t.Li, .Li+1 ; .endr\r\n\taddi\t\t\\ab, \\ab, .Lperloop*\\linesize\t// move to next line\r\n.Lend_cachex\\@:\r\n\r\n\t.else\r\n\r\n\tmovi\t\\aa, (\\size / \\assoc_or1)\r\n\t// Possible improvement: need only loop if \\aa > 1 ;\r\n\t// however \\aa == 1 is highly unlikely.\r\n\tmovi\t\\ab, 0\t\t// to iterate over cache\r\n.Lstart_cachex\\@:\r\n\t.set\t.Li, 0 ;     .rept .Lperloop\r\n\t  \\cainst\t\\ab, .Li*\\linesize\r\n\t.set\t.Li, .Li+1 ; .endr\r\n\taddi\t\t\\ab, \\ab, .Lperloop*\\linesize\t// move to next line\r\n\tbltu\t\t\\ab, \\aa, .Lstart_cachex\\@\r\n\r\n\t.endif\r\n\r\n\t.endm\r\n\r\n\r\n/*\r\n *  Macro to apply a 'hit' cache instruction to a memory region,\r\n *  ie. to any cache entries that cache a specified portion (region) of memory.\r\n *  Takes care of the unaligned cases, ie. may apply to one\r\n *  more cache line than $asize / lineSize if $aaddr is not aligned.\r\n *\r\n *\r\n *  Parameters are:\r\n *\tcainst\tinstruction/macro that takes an address register parameter\r\n *\t\tand an offset parameter (currently always zero)\r\n *\t\tand generates a cache instruction (eg. \"dhi\", \"dhwb\", \"ihi\", etc.)\r\n *\tlinesize_log2\tlog2(size of cache line in bytes)\r\n *\taddr\tregister containing start address of region (clobbered)\r\n *\tasize\tregister containing size of the region in bytes (clobbered)\r\n *\taskew\tunique register used as temporary\r\n *\r\n *  Note: A possible optimization to this macro is to apply the operation\r\n *  to the entire cache if the region exceeds the size of the cache\r\n *  by some empirically determined amount or factor.  Some experimentation\r\n *  is required to determine the appropriate factors, which also need\r\n *  to be tunable if required.\r\n */\r\n\r\n\t.macro\tcache_hit_region\tcainst, linesize_log2, addr, asize, askew\r\n\r\n\t//  Make \\asize the number of iterations:\r\n\textui\t\\askew, \\addr, 0, \\linesize_log2\t// get unalignment amount of \\addr\r\n\tadd\t\\asize, \\asize, \\askew\t\t\t// ... and add it to \\asize\r\n\taddi\t\\asize, \\asize, (1 << \\linesize_log2) - 1\t// round up!\r\n\tsrli\t\\asize, \\asize, \\linesize_log2\r\n\r\n\t//  Iterate over region:\r\n\tfloopnez\t\\asize, cacheh\\@\r\n\t\\cainst\t\t\\addr, 0\r\n\taddi\t\t\\addr, \\addr, (1 << \\linesize_log2)\t// move to next line\r\n\tfloopend\t\\asize, cacheh\\@\r\n\r\n\t.endm\r\n\r\n\r\n\r\n\r\n\r\n/***************************   INSTRUCTION CACHE   ***************************/\r\n\r\n\r\n/*\r\n *  Reset/initialize the instruction cache by simply invalidating it:\r\n *  (need to unlock first also, if cache locking implemented):\r\n *\r\n *  Parameters:\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n */\r\n\t.macro\ticache_reset\taa, ab, loopokay=0\r\n\ticache_unlock_all\t\\aa, \\ab, \\loopokay\r\n\ticache_invalidate_all\t\\aa, \\ab, \\loopokay\r\n\t.endm\r\n\r\n\r\n/*\r\n * Synchronize after an instruction cache operation,\r\n * to be sure everything is in sync with memory as to be\r\n * expected following any previous instruction cache control operations.\r\n *\r\n * Even if a config doesn't have caches, an isync is still needed\r\n * when instructions in any memory are modified, whether by a loader\r\n * or self-modifying code.  Therefore, this macro always produces\r\n * an isync, whether or not an icache is present.\r\n *\r\n * Parameters are:\r\n *\tar\tan address register (temporary) (currently unused, but may be used in future)\r\n */\r\n\t.macro\ticache_sync\tar\r\n\tisync\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Invalidate a single line of the instruction cache.\r\n *  Parameters are:\r\n *\tar\taddress register that contains (virtual) address to invalidate\r\n *\t\t(may get clobbered in a future implementation, but not currently)\r\n *\toffset\t(optional) offset to add to \\ar to compute effective address to invalidate\r\n *\t\t(note: some number of lsbits are ignored)\r\n */\r\n\t.macro\ticache_invalidate_line\tar, offset\r\n#if XCHAL_ICACHE_SIZE > 0\r\n\tihi\t\\ar, \\offset\t\t// invalidate icache line\r\n\t/*\r\n\t *  NOTE:  in some early version of a test chip silicon (SiChip1),\r\n\t *  'ihi' didn't work, so software had to replace it with\r\n\t *  the much more draconian 'iii'\r\n\t *  (which would just invalidate more than it should,\r\n\t *  which should be okay other than the performance hit\r\n\t *  because cache locking did not exist in that version,\r\n\t *  unless user somehow relies on something being cached).\r\n\t *\r\n\t *  #if ... targeting this ancient, now non-existent, test chip silicon ...\r\n\t *\tiii\t\\ar, \\offset\r\n\t *  #endif\r\n\t */\r\n\ticache_sync\t\\ar\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n\r\n/*\r\n *  Invalidate instruction  cache entries that cache a specified portion of memory.\r\n *  Parameters are:\r\n *\tastart\tstart address (register gets clobbered)\r\n *\tasize\tsize of the region in bytes (register gets clobbered)\r\n *\tac\tunique register used as temporary\r\n */\r\n\t.macro\ticache_invalidate_region\tastart, asize, ac\r\n#if XCHAL_ICACHE_SIZE > 0\r\n\t//  Instruction cache region invalidation:\r\n\tcache_hit_region\tihi, XCHAL_ICACHE_LINEWIDTH, \\astart, \\asize, \\ac\r\n\ticache_sync\t\\ac\r\n\t//  End of instruction cache region invalidation\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Invalidate entire instruction cache.\r\n *\r\n *  Parameters:\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n */\r\n\t.macro\ticache_invalidate_all\taa, ab, loopokay=1\r\n#if XCHAL_ICACHE_SIZE > 0\r\n\t//  Instruction cache invalidation:\r\n\tcache_index_all\t\tiii, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, XCHAL_ICACHE_WAYS, \\aa, \\ab, \\loopokay, 1020\r\n\ticache_sync\t\\aa\r\n\t//  End of instruction cache invalidation\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Lock (prefetch & lock) a single line of the instruction cache.\r\n *\r\n *  Parameters are:\r\n *\tar\taddress register that contains (virtual) address to lock\r\n *\t\t(may get clobbered in a future implementation, but not currently)\r\n *\toffset\toffset to add to \\ar to compute effective address to lock\r\n *\t\t(note: some number of lsbits are ignored)\r\n */\r\n\t.macro\ticache_lock_line\tar, offset\r\n#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE\r\n\tipfl\t\\ar, \\offset\t/* prefetch and lock icache line */\r\n\ticache_sync\t\\ar\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Lock (prefetch & lock) a specified portion of memory into the instruction cache.\r\n *  Parameters are:\r\n *\tastart\tstart address (register gets clobbered)\r\n *\tasize\tsize of the region in bytes (register gets clobbered)\r\n *\tac\tunique register used as temporary\r\n */\r\n\t.macro\ticache_lock_region\tastart, asize, ac\r\n#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE\r\n\t//  Instruction cache region lock:\r\n\tcache_hit_region\tipfl, XCHAL_ICACHE_LINEWIDTH, \\astart, \\asize, \\ac\r\n\ticache_sync\t\\ac\r\n\t//  End of instruction cache region lock\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Unlock a single line of the instruction cache.\r\n *\r\n *  Parameters are:\r\n *\tar\taddress register that contains (virtual) address to unlock\r\n *\t\t(may get clobbered in a future implementation, but not currently)\r\n *\toffset\toffset to add to \\ar to compute effective address to unlock\r\n *\t\t(note: some number of lsbits are ignored)\r\n */\r\n\t.macro\ticache_unlock_line\tar, offset\r\n#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE\r\n\tihu\t\\ar, \\offset\t/* unlock icache line */\r\n\ticache_sync\t\\ar\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Unlock a specified portion of memory from the instruction cache.\r\n *  Parameters are:\r\n *\tastart\tstart address (register gets clobbered)\r\n *\tasize\tsize of the region in bytes (register gets clobbered)\r\n *\tac\tunique register used as temporary\r\n */\r\n\t.macro\ticache_unlock_region\tastart, asize, ac\r\n#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE\r\n\t//  Instruction cache region unlock:\r\n\tcache_hit_region\tihu, XCHAL_ICACHE_LINEWIDTH, \\astart, \\asize, \\ac\r\n\ticache_sync\t\\ac\r\n\t//  End of instruction cache region unlock\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Unlock entire instruction cache.\r\n *\r\n *  Parameters:\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n */\r\n\t.macro\ticache_unlock_all\taa, ab, loopokay=1\r\n#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE\r\n\t//  Instruction cache unlock:\r\n\tcache_index_all\t\tiiu, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, 1, \\aa, \\ab, \\loopokay\r\n\ticache_sync\t\\aa\r\n\t//  End of instruction cache unlock\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n\r\n\r\n/***************************   DATA CACHE   ***************************/\r\n\r\n\r\n\r\n/*\r\n *  Reset/initialize the data cache by simply invalidating it\r\n *  (need to unlock first also, if cache locking implemented):\r\n *\r\n *  Parameters:\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n */\r\n\t.macro\tdcache_reset\taa, ab, loopokay=0\r\n\tdcache_unlock_all\t\\aa, \\ab, \\loopokay\r\n\tdcache_invalidate_all\t\\aa, \\ab, \\loopokay\r\n\t.endm\r\n\r\n\r\n\r\n\r\n/*\r\n * Synchronize after a data cache operation,\r\n * to be sure everything is in sync with memory as to be\r\n * expected following any previous data cache control operations.\r\n *\r\n * Parameters are:\r\n *\tar\tan address register (temporary) (currently unused, but may be used in future)\r\n */\r\n\t.macro\tdcache_sync\tar\r\n#if XCHAL_DCACHE_SIZE > 0\r\n\t//  This previous sequence errs on the conservative side (too much so); a DSYNC should be sufficient:\r\n\t//memw\t\t// synchronize data cache changes relative to subsequent memory accesses\r\n\t//isync\t\t// be conservative and ISYNC as well (just to be sure)\r\n\r\n\tdsync\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n * Opt into cache coherence.\r\n *\r\n * Parameters are:\r\n *\tar,at\ttwo scratch address registers (both clobbered)\r\n */\r\n\t.macro\tcache_coherence_on\tar at\r\n#if XCHAL_HAVE_EXTERN_REGS && XCHAL_DCACHE_IS_COHERENT\r\n\tmovi\t\\ar, 1\r\n\tmovi\t\\at, XER_CCON\r\n\twer\t\\ar, \\at\r\n\textw\r\n# endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n * Opt out of cache coherence.\r\n * NOTE:  this is generally preceded by emptying the cache;\r\n * see xthal_cache_coherence_optout() in hal/coherence.c for details.\r\n *\r\n * Parameters are:\r\n *\tar,at\ttwo scratch address registers (both clobbered)\r\n */\r\n\t.macro\tcache_coherence_off\tar at\r\n#if XCHAL_HAVE_EXTERN_REGS && XCHAL_DCACHE_IS_COHERENT\r\n\textw\r\n\tmovi\t\\at, 0\r\n\tmovi\t\\ar, XER_CCON\r\n\twer\t\\at, \\ar\r\n\textw\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n * Synchronize after a data store operation,\r\n * to be sure the stored data is completely off the processor\r\n * (and assuming there is no buffering outside the processor,\r\n *  that the data is in memory).  This may be required to\r\n * ensure that the processor's write buffers are emptied.\r\n * A MEMW followed by a read guarantees this, by definition.\r\n * We also try to make sure the read itself completes.\r\n *\r\n * Parameters are:\r\n *\tar\tan address register (temporary)\r\n */\r\n\t.macro\twrite_sync\tar\r\n\tmemw\t\t\t// ensure previous memory accesses are complete prior to subsequent memory accesses\r\n\tl32i\t\\ar, sp, 0\t// completing this read ensures any previous write has completed, because of MEMW\r\n\t//slot\r\n\tadd\t\\ar, \\ar, \\ar\t// use the result of the read to help ensure the read completes (in future architectures)\r\n\t.endm\r\n\r\n\r\n/*\r\n *  Invalidate a single line of the data cache.\r\n *  Parameters are:\r\n *\tar\taddress register that contains (virtual) address to invalidate\r\n *\t\t(may get clobbered in a future implementation, but not currently)\r\n *\toffset\t(optional) offset to add to \\ar to compute effective address to invalidate\r\n *\t\t(note: some number of lsbits are ignored)\r\n */\r\n\t.macro\tdcache_invalidate_line\tar, offset\r\n#if XCHAL_DCACHE_SIZE > 0\r\n\tdhi\t\\ar, \\offset\r\n\tdcache_sync\t\\ar\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n\r\n\r\n/*\r\n *  Invalidate data cache entries that cache a specified portion of memory.\r\n *  Parameters are:\r\n *\tastart\tstart address (register gets clobbered)\r\n *\tasize\tsize of the region in bytes (register gets clobbered)\r\n *\tac\tunique register used as temporary\r\n */\r\n\t.macro\tdcache_invalidate_region\tastart, asize, ac\r\n#if XCHAL_DCACHE_SIZE > 0\r\n\t//  Data cache region invalidation:\r\n\tcache_hit_region\tdhi, XCHAL_DCACHE_LINEWIDTH, \\astart, \\asize, \\ac\r\n\tdcache_sync\t\\ac\r\n\t//  End of data cache region invalidation\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n#if 0\r\n/*\r\n *  This is a work-around for a bug in SiChip1.\r\n *  To enable the work-around, uncomment this and replace 'dii'\r\n *  with 'dii_s1' everywhere, eg. in the dcache_invalidate_all\r\n *  macro below.\r\n */\r\n\t.macro\tdii_s1\tar, offset\r\n\tdii\t\\ar, \\offset\r\n\tor\t\\ar, \\ar, \\ar\r\n\tor\t\\ar, \\ar, \\ar\r\n\tor\t\\ar, \\ar, \\ar\r\n\tor\t\\ar, \\ar, \\ar\r\n\t.endm\r\n#endif\r\n\r\n\r\n/*\r\n *  Invalidate entire data cache.\r\n *\r\n *  Parameters:\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n */\r\n\t.macro\tdcache_invalidate_all\taa, ab, loopokay=1\r\n#if XCHAL_DCACHE_SIZE > 0\r\n\t//  Data cache invalidation:\r\n\tcache_index_all\t\tdii, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, XCHAL_DCACHE_WAYS, \\aa, \\ab, \\loopokay, 1020\r\n\tdcache_sync\t\\aa\r\n\t//  End of data cache invalidation\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Writeback a single line of the data cache.\r\n *  Parameters are:\r\n *\tar\taddress register that contains (virtual) address to writeback\r\n *\t\t(may get clobbered in a future implementation, but not currently)\r\n *\toffset\toffset to add to \\ar to compute effective address to writeback\r\n *\t\t(note: some number of lsbits are ignored)\r\n */\r\n\t.macro\tdcache_writeback_line\tar, offset\r\n#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK\r\n\tdhwb\t\\ar, \\offset\r\n\tdcache_sync\t\\ar\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Writeback dirty data cache entries that cache a specified portion of memory.\r\n *  Parameters are:\r\n *\tastart\tstart address (register gets clobbered)\r\n *\tasize\tsize of the region in bytes (register gets clobbered)\r\n *\tac\tunique register used as temporary\r\n */\r\n\t.macro\tdcache_writeback_region\t\tastart, asize, ac\r\n#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK\r\n\t//  Data cache region writeback:\r\n\tcache_hit_region\tdhwb, XCHAL_DCACHE_LINEWIDTH, \\astart, \\asize, \\ac\r\n\tdcache_sync\t\\ac\r\n\t//  End of data cache region writeback\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Writeback entire data cache.\r\n *  Parameters:\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n */\r\n\t.macro\tdcache_writeback_all\taa, ab, loopokay=1\r\n#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK\r\n\t//  Data cache writeback:\r\n\tcache_index_all\t\tdiwb, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \\aa, \\ab, \\loopokay\r\n\tdcache_sync\t\\aa\r\n\t//  End of data cache writeback\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Writeback and invalidate a single line of the data cache.\r\n *  Parameters are:\r\n *\tar\taddress register that contains (virtual) address to writeback and invalidate\r\n *\t\t(may get clobbered in a future implementation, but not currently)\r\n *\toffset\toffset to add to \\ar to compute effective address to writeback and invalidate\r\n *\t\t(note: some number of lsbits are ignored)\r\n */\r\n\t.macro\tdcache_writeback_inv_line\tar, offset\r\n#if XCHAL_DCACHE_SIZE > 0\r\n\tdhwbi\t\\ar, \\offset\t/* writeback and invalidate dcache line */\r\n\tdcache_sync\t\\ar\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Writeback and invalidate data cache entries that cache a specified portion of memory.\r\n *  Parameters are:\r\n *\tastart\tstart address (register gets clobbered)\r\n *\tasize\tsize of the region in bytes (register gets clobbered)\r\n *\tac\tunique register used as temporary\r\n */\r\n\t.macro\tdcache_writeback_inv_region\tastart, asize, ac\r\n#if XCHAL_DCACHE_SIZE > 0\r\n\t//  Data cache region writeback and invalidate:\r\n\tcache_hit_region\tdhwbi, XCHAL_DCACHE_LINEWIDTH, \\astart, \\asize, \\ac\r\n\tdcache_sync\t\\ac\r\n\t//  End of data cache region writeback and invalidate\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Writeback and invalidate entire data cache.\r\n *  Parameters:\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n */\r\n\t.macro\tdcache_writeback_inv_all\taa, ab, loopokay=1\r\n#if XCHAL_DCACHE_SIZE > 0\r\n\t//  Data cache writeback and invalidate:\r\n#if XCHAL_DCACHE_IS_WRITEBACK\r\n\tcache_index_all\t\tdiwbi, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \\aa, \\ab, \\loopokay\r\n\tdcache_sync\t\\aa\r\n#else /*writeback*/\r\n\t//  Data cache does not support writeback, so just invalidate: */\r\n\tdcache_invalidate_all\t\\aa, \\ab, \\loopokay\r\n#endif /*writeback*/\r\n\t//  End of data cache writeback and invalidate\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n\r\n/*\r\n *  Lock (prefetch & lock) a single line of the data cache.\r\n *\r\n *  Parameters are:\r\n *\tar\taddress register that contains (virtual) address to lock\r\n *\t\t(may get clobbered in a future implementation, but not currently)\r\n *\toffset\toffset to add to \\ar to compute effective address to lock\r\n *\t\t(note: some number of lsbits are ignored)\r\n */\r\n\t.macro\tdcache_lock_line\tar, offset\r\n#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE\r\n\tdpfl\t\\ar, \\offset\t/* prefetch and lock dcache line */\r\n\tdcache_sync\t\\ar\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Lock (prefetch & lock) a specified portion of memory into the data cache.\r\n *  Parameters are:\r\n *\tastart\tstart address (register gets clobbered)\r\n *\tasize\tsize of the region in bytes (register gets clobbered)\r\n *\tac\tunique register used as temporary\r\n */\r\n\t.macro\tdcache_lock_region\tastart, asize, ac\r\n#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE\r\n\t//  Data cache region lock:\r\n\tcache_hit_region\tdpfl, XCHAL_DCACHE_LINEWIDTH, \\astart, \\asize, \\ac\r\n\tdcache_sync\t\\ac\r\n\t//  End of data cache region lock\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Unlock a single line of the data cache.\r\n *\r\n *  Parameters are:\r\n *\tar\taddress register that contains (virtual) address to unlock\r\n *\t\t(may get clobbered in a future implementation, but not currently)\r\n *\toffset\toffset to add to \\ar to compute effective address to unlock\r\n *\t\t(note: some number of lsbits are ignored)\r\n */\r\n\t.macro\tdcache_unlock_line\tar, offset\r\n#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE\r\n\tdhu\t\\ar, \\offset\t/* unlock dcache line */\r\n\tdcache_sync\t\\ar\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Unlock a specified portion of memory from the data cache.\r\n *  Parameters are:\r\n *\tastart\tstart address (register gets clobbered)\r\n *\tasize\tsize of the region in bytes (register gets clobbered)\r\n *\tac\tunique register used as temporary\r\n */\r\n\t.macro\tdcache_unlock_region\tastart, asize, ac\r\n#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE\r\n\t//  Data cache region unlock:\r\n\tcache_hit_region\tdhu, XCHAL_DCACHE_LINEWIDTH, \\astart, \\asize, \\ac\r\n\tdcache_sync\t\\ac\r\n\t//  End of data cache region unlock\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  Unlock entire data cache.\r\n *\r\n *  Parameters:\r\n *\taa, ab\t\tunique address registers (temporaries)\r\n */\r\n\t.macro\tdcache_unlock_all\taa, ab, loopokay=1\r\n#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE\r\n\t//  Data cache unlock:\r\n\tcache_index_all\t\tdiu, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \\aa, \\ab, \\loopokay\r\n\tdcache_sync\t\\aa\r\n\t//  End of data cache unlock\r\n#endif\r\n\t.endm\r\n\r\n\r\n#endif /*XTENSA_CACHEASM_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/cacheattrasm.h",
    "content": "/*\r\n * xtensa/cacheattrasm.h -- assembler-specific CACHEATTR register related definitions\r\n *\t\t\tthat depend on CORE configuration\r\n *\r\n *  This file is logically part of xtensa/coreasm.h (or perhaps xtensa/cacheasm.h),\r\n *  but is kept separate for modularity / compilation-performance.\r\n */\r\n\r\n/*\r\n * Copyright (c) 2001-2009 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef XTENSA_CACHEATTRASM_H\r\n#define XTENSA_CACHEATTRASM_H\r\n\r\n#include <xtensa/coreasm.h>\r\n\r\n/*  Determine whether cache attributes are controlled using eight 512MB entries:  */\r\n#define XCHAL_CA_8X512\t(XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR \\\r\n\t|| (XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY))\r\n\r\n\r\n/*\r\n *  This header file defines assembler macros of the form:\r\n *\t<x>cacheattr_<func>\r\n *  where:\r\n *\t<x> is 'i', 'd' or absent for instruction, data\r\n *\t\tor both caches; and\r\n *\t<func> indicates the function of the macro.\r\n *\r\n *  The following functions are defined:\r\n *\r\n *  icacheattr_get\r\n *\tReads I-cache CACHEATTR into a2 (clobbers a3-a5).\r\n *\r\n *  dcacheattr_get\r\n *\tReads D-cache CACHEATTR into a2 (clobbers a3-a5).\r\n *\t(Note:  for configs with a real CACHEATTR register, the\r\n *\t above two macros are identical.)\r\n *\r\n *  cacheattr_set\r\n *\tWrites both I-cache and D-cache CACHEATTRs from a2 (a3-a8 clobbered).\r\n *\tWorks even when changing one's own code's attributes.\r\n *\r\n *  icacheattr_is_enabled  label\r\n *\tBranches to \\label if I-cache appears to have been enabled\r\n *\t(eg. if CACHEATTR contains a cache-enabled attribute).\r\n *\t(clobbers a2-a5,SAR)\r\n *\r\n *  dcacheattr_is_enabled  label\r\n *\tBranches to \\label if D-cache appears to have been enabled\r\n *\t(eg. if CACHEATTR contains a cache-enabled attribute).\r\n *\t(clobbers a2-a5,SAR)\r\n *\r\n *  cacheattr_is_enabled  label\r\n *\tBranches to \\label if either I-cache or D-cache appears to have been enabled\r\n *\t(eg. if CACHEATTR contains a cache-enabled attribute).\r\n *\t(clobbers a2-a5,SAR)\r\n *\r\n *  The following macros are only defined under certain conditions:\r\n *\r\n *  icacheattr_set\t(if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)\r\n *\tWrites I-cache CACHEATTR from a2 (a3-a8 clobbered).\r\n *\r\n *  dcacheattr_set\t(if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)\r\n *\tWrites D-cache CACHEATTR from a2 (a3-a8 clobbered).\r\n */\r\n\r\n\r\n\r\n/***************************   GENERIC -- ALL CACHES   ***************************/\r\n\r\n/*\r\n *  _cacheattr_get\r\n *\r\n *  (Internal macro.)\r\n *  Returns value of CACHEATTR register (or closest equivalent) in a2.\r\n *  \r\n *  Entry:\r\n *\t(none)\r\n *  Exit:\r\n *\ta2\tvalue read from CACHEATTR\r\n *\ta3-a5\tclobbered (temporaries)\r\n */\r\n\t.macro\t_cacheattr_get\ttlb\r\n#if XCHAL_HAVE_CACHEATTR\r\n\trsr\ta2, CACHEATTR\r\n#elif XCHAL_CA_8X512\r\n\t//  We have a config that \"mimics\" CACHEATTR using a simplified\r\n\t//  \"MMU\" composed of a single statically-mapped way.\r\n\t//  DTLB and ITLB are independent, so there's no single\r\n\t//  cache attribute that can describe both.  So for now\r\n\t//  just return the DTLB state.\r\n\tmovi\ta5, 0xE0000000\r\n\tmovi\ta2, 0\r\n\tmovi\ta3, XCHAL_SPANNING_WAY\r\n1:\tadd\ta3, a3, a5\t// next segment\r\n\tr&tlb&1\ta4, a3\t\t// get PPN+CA of segment at 0xE0000000, 0xC0000000, ..., 0\r\n\tdsync\t// interlock???\r\n\tslli\ta2, a2, 4\r\n\textui\ta4, a4, 0, 4\t// extract CA\r\n\tor\ta2, a2, a4\r\n\tbgeui\ta3, 16, 1b\r\n#else\r\n\t//  This macro isn't applicable to arbitrary MMU configurations.\r\n\t//  Just return zero.\r\n\tmovi\ta2, 0\r\n#endif\r\n\t.endm\r\n\r\n\t.macro\ticacheattr_get\r\n\t_cacheattr_get\titlb\r\n\t.endm\r\n\r\n\t.macro\tdcacheattr_get\r\n\t_cacheattr_get\tdtlb\r\n\t.endm\r\n\r\n\r\n/* Default (powerup/reset) value of CACHEATTR,\r\n   all BYPASS mode (ie. disabled/bypassed caches): */\r\n#if XCHAL_HAVE_PTP_MMU\r\n# define XCHAL_CACHEATTR_ALL_BYPASS\t0x33333333\r\n#else\r\n# define XCHAL_CACHEATTR_ALL_BYPASS\t0x22222222\r\n#endif\r\n\r\n#if XCHAL_CA_8X512\r\n\r\n#if XCHAL_HAVE_PTP_MMU\r\n# define XCHAL_FCA_ENAMASK\t0x0AA0\t/* bitmap of fetch attributes that require enabled icache */\r\n# define XCHAL_LCA_ENAMASK\t0x0FF0\t/* bitmap of load  attributes that require enabled dcache */\r\n# define XCHAL_SCA_ENAMASK\t0x0CC0\t/* bitmap of store attributes that require enabled dcache */\r\n#else\r\n# define XCHAL_FCA_ENAMASK\t0x003A\t/* bitmap of fetch attributes that require enabled icache */\r\n# define XCHAL_LCA_ENAMASK\t0x0033\t/* bitmap of load  attributes that require enabled dcache */\r\n# define XCHAL_SCA_ENAMASK\t0x0033\t/* bitmap of store attributes that require enabled dcache */\r\n#endif\r\n#define XCHAL_LSCA_ENAMASK\t(XCHAL_LCA_ENAMASK|XCHAL_SCA_ENAMASK)\t/* l/s attrs requiring enabled dcache */\r\n#define XCHAL_ALLCA_ENAMASK\t(XCHAL_FCA_ENAMASK|XCHAL_LSCA_ENAMASK)\t/* all attrs requiring enabled caches */\r\n\r\n/*\r\n *  _cacheattr_is_enabled\r\n *\r\n *  (Internal macro.)\r\n *  Branches to \\label if CACHEATTR in a2 indicates an enabled\r\n *  cache, using mask in a3.\r\n *\r\n *  Parameters:\r\n *\tlabel\twhere to branch to if cache is enabled\r\n *  Entry:\r\n *\ta2\tcontains CACHEATTR value used to determine whether\r\n *\t\tcaches are enabled\r\n *\ta3\t16-bit constant where each bit correspond to\r\n *\t\tone of the 16 possible CA values (in a CACHEATTR mask);\r\n *\t\tCA values that indicate the cache is enabled\r\n *\t\thave their corresponding bit set in this mask\r\n *\t\t(eg. use XCHAL_xCA_ENAMASK , above)\r\n *  Exit:\r\n *\ta2,a4,a5\tclobbered\r\n *\tSAR\t\tclobbered\r\n */\r\n\t.macro\t_cacheattr_is_enabled\tlabel\r\n\tmovi\ta4, 8\t\t// loop 8 times\r\n.Lcaife\\@:\r\n\textui\ta5, a2, 0, 4\t// get CA nibble\r\n\tssr\ta5\t\t// index into mask according to CA...\r\n\tsrl\ta5, a3\t\t// ...and get CA's mask bit in a5 bit 0\r\n\tbbsi.l\ta5, 0, \\label\t// if CA indicates cache enabled, jump to label\r\n\tsrli\ta2, a2, 4\t// next nibble\r\n\taddi\ta4, a4, -1\r\n\tbnez\ta4, .Lcaife\\@\t// loop for each nibble\r\n\t.endm\r\n\r\n#else /* XCHAL_CA_8X512 */\r\n\t.macro\t_cacheattr_is_enabled\tlabel\r\n\tj\t\\label\t\t// macro not applicable, assume caches always enabled\r\n\t.endm\r\n#endif /* XCHAL_CA_8X512 */\r\n\r\n\r\n\r\n/*\r\n *  icacheattr_is_enabled\r\n *\r\n *  Branches to \\label if I-cache is enabled.\r\n *\r\n *  Parameters:\r\n *\tlabel\twhere to branch to if icache is enabled\r\n *  Entry:\r\n *\t(none)\r\n *  Exit:\r\n *\ta2-a5, SAR\tclobbered (temporaries)\r\n */\r\n\t.macro\ticacheattr_is_enabled\tlabel\r\n#if XCHAL_CA_8X512\r\n\ticacheattr_get\r\n\tmovi\ta3, XCHAL_FCA_ENAMASK\r\n#endif\r\n\t_cacheattr_is_enabled\t\\label\r\n\t.endm\r\n\r\n/*\r\n *  dcacheattr_is_enabled\r\n *\r\n *  Branches to \\label if D-cache is enabled.\r\n *\r\n *  Parameters:\r\n *\tlabel\twhere to branch to if dcache is enabled\r\n *  Entry:\r\n *\t(none)\r\n *  Exit:\r\n *\ta2-a5, SAR\tclobbered (temporaries)\r\n */\r\n\t.macro\tdcacheattr_is_enabled\tlabel\r\n#if XCHAL_CA_8X512\r\n\tdcacheattr_get\r\n\tmovi\ta3, XCHAL_LSCA_ENAMASK\r\n#endif\r\n\t_cacheattr_is_enabled\t\\label\r\n\t.endm\r\n\r\n/*\r\n *  cacheattr_is_enabled\r\n *\r\n *  Branches to \\label if either I-cache or D-cache is enabled.\r\n *\r\n *  Parameters:\r\n *\tlabel\twhere to branch to if a cache is enabled\r\n *  Entry:\r\n *\t(none)\r\n *  Exit:\r\n *\ta2-a5, SAR\tclobbered (temporaries)\r\n */\r\n\t.macro\tcacheattr_is_enabled\tlabel\r\n#if XCHAL_HAVE_CACHEATTR\r\n\trsr\ta2, CACHEATTR\r\n\tmovi\ta3, XCHAL_ALLCA_ENAMASK\r\n#elif XCHAL_CA_8X512\r\n\ticacheattr_get\r\n\tmovi\ta3, XCHAL_FCA_ENAMASK\r\n\t_cacheattr_is_enabled\t\\label\r\n\tdcacheattr_get\r\n\tmovi\ta3, XCHAL_LSCA_ENAMASK\r\n#endif\r\n\t_cacheattr_is_enabled\t\\label\r\n\t.endm\r\n\r\n\r\n\r\n/*\r\n *  The ISA does not have a defined way to change the\r\n *  instruction cache attributes of the running code,\r\n *  ie. of the memory area that encloses the current PC.\r\n *  However, each micro-architecture (or class of\r\n *  configurations within a micro-architecture)\r\n *  provides a way to deal with this issue.\r\n *\r\n *  Here are a few macros used to implement the relevant\r\n *  approach taken.\r\n */\r\n\r\n#if XCHAL_CA_8X512 && !XCHAL_HAVE_CACHEATTR\r\n\t//  We have a config that \"mimics\" CACHEATTR using a simplified\r\n\t//  \"MMU\" composed of a single statically-mapped way.\r\n\r\n/*\r\n *  icacheattr_set\r\n *\r\n *  Entry:\r\n *\ta2\t\tcacheattr value to set\r\n *  Exit:\r\n *\ta2\t\tunchanged\r\n *\ta3-a8\t\tclobbered (temporaries)\r\n */\r\n\t.macro\ticacheattr_set\r\n\r\n\tmovi\ta5, 0xE0000000\t// mask of upper 3 bits\r\n\tmovi\ta6, 3f\t\t// PC where ITLB is set\r\n\tmovi\ta3, XCHAL_SPANNING_WAY\t// start at region 0 (0 .. 7)\r\n\tmov\ta7, a2\t\t// copy a2 so it doesn't get clobbered\r\n\tand\ta6, a6, a5\t// upper 3 bits of local PC area\r\n\tj\t3f\r\n\r\n\t//  Use micro-architecture specific method.\r\n\t//  The following 4-instruction sequence is aligned such that\r\n\t//  it all fits within a single I-cache line.  Sixteen byte\r\n\t//  alignment is sufficient for this (using XCHAL_ICACHE_LINESIZE\r\n\t//  actually causes problems because that can be greater than\r\n\t//  the alignment of the reset vector, where this macro is often\r\n\t//  invoked, which would cause the linker to align the reset\r\n\t//  vector code away from the reset vector!!).\r\n\t.begin\tno-transform\r\n\t.align\t16 /*XCHAL_ICACHE_LINESIZE*/\r\n1:\twitlb\ta4, a3\t\t// write wired PTE (CA, no PPN) of 512MB segment to ITLB\r\n\tisync\r\n\t.end\tno-transform\r\n\tnop\r\n\tnop\r\n\r\n\tsub\ta3, a3, a5\t// next segment (add 0x20000000)\r\n\tbltui\ta3, 16, 4f\t// done?\r\n\r\n\t//  Note that in the WITLB loop, we don't do any load/stores\r\n\t//  (may not be an issue here, but it is important in the DTLB case).\r\n2:\tsrli\ta7, a7, 4\t// next CA\r\n3:\r\n# if XCHAL_HAVE_MIMIC_CACHEATTR\r\n\textui\ta4, a7, 0, 4\t// extract CA to set\r\n# else\t/* have translation, preserve it: */\r\n\tritlb1\ta8, a3\t\t// get current PPN+CA of segment\r\n\t//dsync\t// interlock???\r\n\textui\ta4, a7, 0, 4\t// extract CA to set\r\n\tsrli\ta8, a8, 4\t// clear CA but keep PPN ...\r\n\tslli\ta8, a8, 4\t// ...\r\n\tadd\ta4, a4, a8\t// combine new CA with PPN to preserve\r\n# endif\r\n\tbeq\ta3, a6, 1b\t// current PC's region? if so, do it in a safe way\r\n\twitlb\ta4, a3\t\t// write wired PTE (CA [+PPN]) of 512MB segment to ITLB\r\n\tsub\ta3, a3, a5\t// next segment (add 0x20000000)\r\n\tbgeui\ta3, 16, 2b\r\n\tisync\t\t\t// make sure all ifetch changes take effect\r\n4:\r\n\t.endm\t// icacheattr_set\r\n\r\n\r\n/*\r\n *  dcacheattr_set\r\n *\r\n *  Entry:\r\n *\ta2\t\tcacheattr value to set\r\n *  Exit:\r\n *\ta2\t\tunchanged\r\n *\ta3-a8\t\tclobbered (temporaries)\r\n */\r\n\r\n\t.macro\tdcacheattr_set\r\n\r\n\tmovi\ta5, 0xE0000000\t// mask of upper 3 bits\r\n\tmovi\ta3, XCHAL_SPANNING_WAY\t// start at region 0 (0 .. 7)\r\n\tmov\ta7, a2\t\t// copy a2 so it doesn't get clobbered\r\n\t//  Note that in the WDTLB loop, we don't do any load/stores\r\n2:\t//  (including implicit l32r via movi) because it isn't safe.\r\n# if XCHAL_HAVE_MIMIC_CACHEATTR\r\n\textui\ta4, a7, 0, 4\t// extract CA to set\r\n# else\t/* have translation, preserve it: */\r\n\trdtlb1\ta8, a3\t\t// get current PPN+CA of segment\r\n\t//dsync\t// interlock???\r\n\textui\ta4, a7, 0, 4\t// extract CA to set\r\n\tsrli\ta8, a8, 4\t// clear CA but keep PPN ...\r\n\tslli\ta8, a8, 4\t// ...\r\n\tadd\ta4, a4, a8\t// combine new CA with PPN to preserve\r\n# endif\r\n\twdtlb\ta4, a3\t\t// write wired PTE (CA [+PPN]) of 512MB segment to DTLB\r\n\tsub\ta3, a3, a5\t// next segment (add 0x20000000)\r\n\tsrli\ta7, a7, 4\t// next CA\r\n\tbgeui\ta3, 16, 2b\r\n\tdsync\t\t\t// make sure all data path changes take effect\r\n\t.endm\t// dcacheattr_set\r\n\r\n#endif /* XCHAL_CA_8X512 && !XCHAL_HAVE_CACHEATTR */\r\n\r\n\r\n\r\n/*\r\n *  cacheattr_set\r\n *\r\n *  Macro that sets the current CACHEATTR safely\r\n *  (both i and d) according to the current contents of a2.\r\n *  It works even when changing the cache attributes of\r\n *  the currently running code.\r\n *\r\n *  Entry:\r\n *\ta2\t\tcacheattr value to set\r\n *  Exit:\r\n *\ta2\t\tunchanged\r\n *\ta3-a8\t\tclobbered (temporaries)\r\n */\r\n\t.macro\tcacheattr_set\r\n\r\n#if XCHAL_HAVE_CACHEATTR\r\n# if XCHAL_ICACHE_LINESIZE < 4\r\n\t//  No i-cache, so can always safely write to CACHEATTR:\r\n\twsr\ta2, CACHEATTR\r\n# else\r\n\t//  The Athens micro-architecture, when using the old\r\n\t//  exception architecture option (ie. with the CACHEATTR register)\r\n\t//  allows changing the cache attributes of the running code\r\n\t//  using the following exact sequence aligned to be within\r\n\t//  an instruction cache line.  (NOTE: using XCHAL_ICACHE_LINESIZE\r\n\t//  alignment actually causes problems because that can be greater\r\n\t//  than the alignment of the reset vector, where this macro is often\r\n\t//  invoked, which would cause the linker to align the reset\r\n\t//  vector code away from the reset vector!!).\r\n\tj\t1f\r\n\t.begin\tno-transform\r\n\t.align\t16 /*XCHAL_ICACHE_LINESIZE*/\t// align to within an I-cache line\r\n1:\twsr\ta2, CACHEATTR\r\n\tisync\r\n\t.end\tno-transform\r\n\tnop\r\n\tnop\r\n# endif\r\n#elif XCHAL_CA_8X512\r\n\t//  DTLB and ITLB are independent, but to keep semantics\r\n\t//  of this macro we simply write to both.\r\n\ticacheattr_set\r\n\tdcacheattr_set\r\n#else\r\n\t//  This macro isn't applicable to arbitrary MMU configurations.\r\n\t//  Do nothing in this case.\r\n#endif\r\n\t.endm\r\n\r\n\r\n#endif /*XTENSA_CACHEATTRASM_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/config/core-isa.h",
    "content": "/* \r\n * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa\r\n *\t\t\t\tprocessor CORE configuration\r\n *\r\n *  See <xtensa/config/core.h>, which includes this file, for more details.\r\n */\r\n\r\n/* Xtensa processor core configuration information.\r\n\r\n   Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */\r\n\r\n#ifndef _XTENSA_CORE_CONFIGURATION_H\r\n#define _XTENSA_CORE_CONFIGURATION_H\r\n\r\n\r\n/****************************************************************************\r\n\t    Parameters Useful for Any Code, USER or PRIVILEGED\r\n ****************************************************************************/\r\n\r\n/*\r\n *  Note:  Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is\r\n *  configured, and a value of 0 otherwise.  These macros are always defined.\r\n */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tISA\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_HAVE_BE\t\t\t0\t/* big-endian byte ordering */\r\n#define XCHAL_HAVE_WINDOWED\t\t0\t/* windowed registers option */\r\n#define XCHAL_NUM_AREGS\t\t\t16\t/* num of physical addr regs */\r\n#define XCHAL_NUM_AREGS_LOG2\t\t4\t/* log2(XCHAL_NUM_AREGS) */\r\n#define XCHAL_MAX_INSTRUCTION_SIZE\t3\t/* max instr bytes (3..8) */\r\n#define XCHAL_HAVE_DEBUG\t\t1\t/* debug option */\r\n#define XCHAL_HAVE_DENSITY\t\t1\t/* 16-bit instructions */\r\n#define XCHAL_HAVE_LOOPS\t\t0\t/* zero-overhead loops */\r\n#define XCHAL_HAVE_NSA\t\t\t1\t/* NSA/NSAU instructions */\r\n#define XCHAL_HAVE_MINMAX\t\t0\t/* MIN/MAX instructions */\r\n#define XCHAL_HAVE_SEXT\t\t\t0\t/* SEXT instruction */\r\n#define XCHAL_HAVE_CLAMPS\t\t0\t/* CLAMPS instruction */\r\n#define XCHAL_HAVE_MUL16\t\t1\t/* MUL16S/MUL16U instructions */\r\n#define XCHAL_HAVE_MUL32\t\t1\t/* MULL instruction */\r\n#define XCHAL_HAVE_MUL32_HIGH\t\t0\t/* MULUH/MULSH instructions */\r\n#define XCHAL_HAVE_DIV32\t\t0\t/* QUOS/QUOU/REMS/REMU instructions */\r\n#define XCHAL_HAVE_L32R\t\t\t1\t/* L32R instruction */\r\n#define XCHAL_HAVE_ABSOLUTE_LITERALS\t1\t/* non-PC-rel (extended) L32R */\r\n#define XCHAL_HAVE_CONST16\t\t0\t/* CONST16 instruction */\r\n#define XCHAL_HAVE_ADDX\t\t\t1\t/* ADDX#/SUBX# instructions */\r\n#define XCHAL_HAVE_WIDE_BRANCHES\t0\t/* B*.W18 or B*.W15 instr's */\r\n#define XCHAL_HAVE_PREDICTED_BRANCHES\t0\t/* B[EQ/EQZ/NE/NEZ]T instr's */\r\n#define XCHAL_HAVE_CALL4AND12\t\t0\t/* (obsolete option) */\r\n#define XCHAL_HAVE_ABS\t\t\t1\t/* ABS instruction */\r\n/*#define XCHAL_HAVE_POPC\t\t0*/\t/* POPC instruction */\r\n/*#define XCHAL_HAVE_CRC\t\t0*/\t/* CRC instruction */\r\n#define XCHAL_HAVE_RELEASE_SYNC\t\t0\t/* L32AI/S32RI instructions */\r\n#define XCHAL_HAVE_S32C1I\t\t0\t/* S32C1I instruction */\r\n#define XCHAL_HAVE_SPECULATION\t\t0\t/* speculation */\r\n#define XCHAL_HAVE_FULL_RESET\t\t1\t/* all regs/state reset */\r\n#define XCHAL_NUM_CONTEXTS\t\t1\t/* */\r\n#define XCHAL_NUM_MISC_REGS\t\t0\t/* num of scratch regs (0..4) */\r\n#define XCHAL_HAVE_TAP_MASTER\t\t0\t/* JTAG TAP control instr's */\r\n#define XCHAL_HAVE_PRID\t\t\t1\t/* processor ID register */\r\n#define XCHAL_HAVE_EXTERN_REGS\t\t1\t/* WER/RER instructions */\r\n#define XCHAL_HAVE_MP_INTERRUPTS\t0\t/* interrupt distributor port */\r\n#define XCHAL_HAVE_MP_RUNSTALL\t\t0\t/* core RunStall control port */\r\n#define XCHAL_HAVE_THREADPTR\t\t0\t/* THREADPTR register */\r\n#define XCHAL_HAVE_BOOLEANS\t\t0\t/* boolean registers */\r\n#define XCHAL_HAVE_CP\t\t\t0\t/* CPENABLE reg (coprocessor) */\r\n#define XCHAL_CP_MAXCFG\t\t\t0\t/* max allowed cp id plus one */\r\n#define XCHAL_HAVE_MAC16\t\t0\t/* MAC16 package */\r\n#define XCHAL_HAVE_VECTORFPU2005\t0\t/* vector floating-point pkg */\r\n#define XCHAL_HAVE_FP\t\t\t0\t/* floating point pkg */\r\n#define XCHAL_HAVE_DFP\t\t\t0\t/* double precision FP pkg */\r\n#define XCHAL_HAVE_DFP_accel\t\t0\t/* double precision FP acceleration pkg */\r\n#define XCHAL_HAVE_VECTRA1\t\t0\t/* Vectra I  pkg */\r\n#define XCHAL_HAVE_VECTRALX\t\t0\t/* Vectra LX pkg */\r\n#define XCHAL_HAVE_HIFIPRO\t\t0\t/* HiFiPro Audio Engine pkg */\r\n#define XCHAL_HAVE_HIFI2\t\t0\t/* HiFi2 Audio Engine pkg */\r\n#define XCHAL_HAVE_CONNXD2\t\t0\t/* ConnX D2 pkg */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tMISC\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_NUM_WRITEBUFFER_ENTRIES\t1\t/* size of write buffer */\r\n#define XCHAL_INST_FETCH_WIDTH\t\t4\t/* instr-fetch width in bytes */\r\n#define XCHAL_DATA_WIDTH\t\t4\t/* data width in bytes */\r\n/*  In T1050, applies to selected core load and store instructions (see ISA): */\r\n#define XCHAL_UNALIGNED_LOAD_EXCEPTION\t1\t/* unaligned loads cause exc. */\r\n#define XCHAL_UNALIGNED_STORE_EXCEPTION\t1\t/* unaligned stores cause exc.*/\r\n#define XCHAL_UNALIGNED_LOAD_HW\t\t0\t/* unaligned loads work in hw */\r\n#define XCHAL_UNALIGNED_STORE_HW\t0\t/* unaligned stores work in hw*/\r\n\r\n#define XCHAL_SW_VERSION\t\t800001\t/* sw version of this header */\r\n\r\n#define XCHAL_CORE_ID\t\t\t\"lx106\"\t/* alphanum core name\r\n\t\t\t\t\t\t   (CoreID) set in the Xtensa\r\n\t\t\t\t\t\t   Processor Generator */\r\n\r\n#define XCHAL_BUILD_UNIQUE_ID\t\t0x0002B6F6\t/* 22-bit sw build ID */\r\n\r\n/*\r\n *  These definitions describe the hardware targeted by this software.\r\n */\r\n#define XCHAL_HW_CONFIGID0\t\t0xC28CDAFA\t/* ConfigID hi 32 bits*/\r\n#define XCHAL_HW_CONFIGID1\t\t0x1082B6F6\t/* ConfigID lo 32 bits*/\r\n#define XCHAL_HW_VERSION_NAME\t\t\"LX3.0.1\"\t/* full version name */\r\n#define XCHAL_HW_VERSION_MAJOR\t\t2300\t/* major ver# of targeted hw */\r\n#define XCHAL_HW_VERSION_MINOR\t\t1\t/* minor ver# of targeted hw */\r\n#define XCHAL_HW_VERSION\t\t230001\t/* major*100+minor */\r\n#define XCHAL_HW_REL_LX3\t\t1\r\n#define XCHAL_HW_REL_LX3_0\t\t1\r\n#define XCHAL_HW_REL_LX3_0_1\t\t1\r\n#define XCHAL_HW_CONFIGID_RELIABLE\t1\r\n/*  If software targets a *range* of hardware versions, these are the bounds: */\r\n#define XCHAL_HW_MIN_VERSION_MAJOR\t2300\t/* major v of earliest tgt hw */\r\n#define XCHAL_HW_MIN_VERSION_MINOR\t1\t/* minor v of earliest tgt hw */\r\n#define XCHAL_HW_MIN_VERSION\t\t230001\t/* earliest targeted hw */\r\n#define XCHAL_HW_MAX_VERSION_MAJOR\t2300\t/* major v of latest tgt hw */\r\n#define XCHAL_HW_MAX_VERSION_MINOR\t1\t/* minor v of latest tgt hw */\r\n#define XCHAL_HW_MAX_VERSION\t\t230001\t/* latest targeted hw */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tCACHE\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_ICACHE_LINESIZE\t\t4\t/* I-cache line size in bytes */\r\n#define XCHAL_DCACHE_LINESIZE\t\t4\t/* D-cache line size in bytes */\r\n#define XCHAL_ICACHE_LINEWIDTH\t\t2\t/* log2(I line size in bytes) */\r\n#define XCHAL_DCACHE_LINEWIDTH\t\t2\t/* log2(D line size in bytes) */\r\n\r\n#define XCHAL_ICACHE_SIZE\t\t0\t/* I-cache size in bytes or 0 */\r\n#define XCHAL_DCACHE_SIZE\t\t0\t/* D-cache size in bytes or 0 */\r\n\r\n#define XCHAL_DCACHE_IS_WRITEBACK\t0\t/* writeback feature */\r\n#define XCHAL_DCACHE_IS_COHERENT\t0\t/* MP coherence feature */\r\n\r\n#define XCHAL_HAVE_PREFETCH\t\t0\t/* PREFCTL register */\r\n\r\n\r\n\r\n\r\n/****************************************************************************\r\n    Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code\r\n ****************************************************************************/\r\n\r\n\r\n#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tCACHE\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_HAVE_PIF\t\t\t1\t/* any outbound PIF present */\r\n\r\n/*  If present, cache size in bytes == (ways * 2^(linewidth + setwidth)).  */\r\n\r\n/*  Number of cache sets in log2(lines per way):  */\r\n#define XCHAL_ICACHE_SETWIDTH\t\t0\r\n#define XCHAL_DCACHE_SETWIDTH\t\t0\r\n\r\n/*  Cache set associativity (number of ways):  */\r\n#define XCHAL_ICACHE_WAYS\t\t1\r\n#define XCHAL_DCACHE_WAYS\t\t1\r\n\r\n/*  Cache features:  */\r\n#define XCHAL_ICACHE_LINE_LOCKABLE\t0\r\n#define XCHAL_DCACHE_LINE_LOCKABLE\t0\r\n#define XCHAL_ICACHE_ECC_PARITY\t\t0\r\n#define XCHAL_DCACHE_ECC_PARITY\t\t0\r\n\r\n/*  Cache access size in bytes (affects operation of SICW instruction):  */\r\n#define XCHAL_ICACHE_ACCESS_SIZE\t1\r\n#define XCHAL_DCACHE_ACCESS_SIZE\t1\r\n\r\n/*  Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits):  */\r\n#define XCHAL_CA_BITS\t\t\t4\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tINTERNAL I/D RAM/ROMs and XLMI\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_NUM_INSTROM\t\t1\t/* number of core instr. ROMs */\r\n#define XCHAL_NUM_INSTRAM\t\t2\t/* number of core instr. RAMs */\r\n#define XCHAL_NUM_DATAROM\t\t1\t/* number of core data ROMs */\r\n#define XCHAL_NUM_DATARAM\t\t2\t/* number of core data RAMs */\r\n#define XCHAL_NUM_URAM\t\t\t0\t/* number of core unified RAMs*/\r\n#define XCHAL_NUM_XLMI\t\t\t1\t/* number of core XLMI ports */\r\n\r\n/*  Instruction ROM 0:  */\r\n#define XCHAL_INSTROM0_VADDR\t\t0x40200000\r\n#define XCHAL_INSTROM0_PADDR\t\t0x40200000\r\n#define XCHAL_INSTROM0_SIZE\t\t1048576\r\n#define XCHAL_INSTROM0_ECC_PARITY\t0\r\n\r\n/*  Instruction RAM 0:  */\r\n#define XCHAL_INSTRAM0_VADDR\t\t0x40000000\r\n#define XCHAL_INSTRAM0_PADDR\t\t0x40000000\r\n#define XCHAL_INSTRAM0_SIZE\t\t1048576\r\n#define XCHAL_INSTRAM0_ECC_PARITY\t0\r\n\r\n/*  Instruction RAM 1:  */\r\n#define XCHAL_INSTRAM1_VADDR\t\t0x40100000\r\n#define XCHAL_INSTRAM1_PADDR\t\t0x40100000\r\n#define XCHAL_INSTRAM1_SIZE\t\t1048576\r\n#define XCHAL_INSTRAM1_ECC_PARITY\t0\r\n\r\n/*  Data ROM 0:  */\r\n#define XCHAL_DATAROM0_VADDR\t\t0x3FF40000\r\n#define XCHAL_DATAROM0_PADDR\t\t0x3FF40000\r\n#define XCHAL_DATAROM0_SIZE\t\t262144\r\n#define XCHAL_DATAROM0_ECC_PARITY\t0\r\n\r\n/*  Data RAM 0:  */\r\n#define XCHAL_DATARAM0_VADDR\t\t0x3FFC0000\r\n#define XCHAL_DATARAM0_PADDR\t\t0x3FFC0000\r\n#define XCHAL_DATARAM0_SIZE\t\t262144\r\n#define XCHAL_DATARAM0_ECC_PARITY\t0\r\n\r\n/*  Data RAM 1:  */\r\n#define XCHAL_DATARAM1_VADDR\t\t0x3FF80000\r\n#define XCHAL_DATARAM1_PADDR\t\t0x3FF80000\r\n#define XCHAL_DATARAM1_SIZE\t\t262144\r\n#define XCHAL_DATARAM1_ECC_PARITY\t0\r\n\r\n/*  XLMI Port 0:  */\r\n#define XCHAL_XLMI0_VADDR\t\t0x3FF00000\r\n#define XCHAL_XLMI0_PADDR\t\t0x3FF00000\r\n#define XCHAL_XLMI0_SIZE\t\t262144\r\n#define XCHAL_XLMI0_ECC_PARITY\t0\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tINTERRUPTS and TIMERS\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_HAVE_INTERRUPTS\t\t1\t/* interrupt option */\r\n#define XCHAL_HAVE_HIGHPRI_INTERRUPTS\t1\t/* med/high-pri. interrupts */\r\n#define XCHAL_HAVE_NMI\t\t\t1\t/* non-maskable interrupt */\r\n#define XCHAL_HAVE_CCOUNT\t\t1\t/* CCOUNT reg. (timer option) */\r\n#define XCHAL_NUM_TIMERS\t\t1\t/* number of CCOMPAREn regs */\r\n#define XCHAL_NUM_INTERRUPTS\t\t15\t/* number of interrupts */\r\n#define XCHAL_NUM_INTERRUPTS_LOG2\t4\t/* ceil(log2(NUM_INTERRUPTS)) */\r\n#define XCHAL_NUM_EXTINTERRUPTS\t\t13\t/* num of external interrupts */\r\n#define XCHAL_NUM_INTLEVELS\t\t2\t/* number of interrupt levels\r\n\t\t\t\t\t\t   (not including level zero) */\r\n#define XCHAL_EXCM_LEVEL\t\t1\t/* level masked by PS.EXCM */\r\n\t/* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are \"medium priority\") */\r\n\r\n/*  Masks of interrupts at each interrupt level:  */\r\n#define XCHAL_INTLEVEL1_MASK\t\t0x00003FFF\r\n#define XCHAL_INTLEVEL2_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL3_MASK\t\t0x00004000\r\n#define XCHAL_INTLEVEL4_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL5_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL6_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL7_MASK\t\t0x00000000\r\n\r\n/*  Masks of interrupts at each range 1..n of interrupt levels:  */\r\n#define XCHAL_INTLEVEL1_ANDBELOW_MASK\t0x00003FFF\r\n#define XCHAL_INTLEVEL2_ANDBELOW_MASK\t0x00003FFF\r\n#define XCHAL_INTLEVEL3_ANDBELOW_MASK\t0x00007FFF\r\n#define XCHAL_INTLEVEL4_ANDBELOW_MASK\t0x00007FFF\r\n#define XCHAL_INTLEVEL5_ANDBELOW_MASK\t0x00007FFF\r\n#define XCHAL_INTLEVEL6_ANDBELOW_MASK\t0x00007FFF\r\n#define XCHAL_INTLEVEL7_ANDBELOW_MASK\t0x00007FFF\r\n\r\n/*  Level of each interrupt:  */\r\n#define XCHAL_INT0_LEVEL\t\t1\r\n#define XCHAL_INT1_LEVEL\t\t1\r\n#define XCHAL_INT2_LEVEL\t\t1\r\n#define XCHAL_INT3_LEVEL\t\t1\r\n#define XCHAL_INT4_LEVEL\t\t1\r\n#define XCHAL_INT5_LEVEL\t\t1\r\n#define XCHAL_INT6_LEVEL\t\t1\r\n#define XCHAL_INT7_LEVEL\t\t1\r\n#define XCHAL_INT8_LEVEL\t\t1\r\n#define XCHAL_INT9_LEVEL\t\t1\r\n#define XCHAL_INT10_LEVEL\t\t1\r\n#define XCHAL_INT11_LEVEL\t\t1\r\n#define XCHAL_INT12_LEVEL\t\t1\r\n#define XCHAL_INT13_LEVEL\t\t1\r\n#define XCHAL_INT14_LEVEL\t\t3\r\n#define XCHAL_DEBUGLEVEL\t\t2\t/* debug interrupt level */\r\n#define XCHAL_HAVE_DEBUG_EXTERN_INT\t1\t/* OCD external db interrupt */\r\n#define XCHAL_NMILEVEL\t\t\t3\t/* NMI \"level\" (for use with\r\n\t\t\t\t\t\t   EXCSAVE/EPS/EPC_n, RFI n) */\r\n\r\n/*  Type of each interrupt:  */\r\n#define XCHAL_INT0_TYPE \tXTHAL_INTTYPE_EXTERN_LEVEL\r\n#define XCHAL_INT1_TYPE \tXTHAL_INTTYPE_EXTERN_LEVEL\r\n#define XCHAL_INT2_TYPE \tXTHAL_INTTYPE_EXTERN_LEVEL\r\n#define XCHAL_INT3_TYPE \tXTHAL_INTTYPE_EXTERN_LEVEL\r\n#define XCHAL_INT4_TYPE \tXTHAL_INTTYPE_EXTERN_LEVEL\r\n#define XCHAL_INT5_TYPE \tXTHAL_INTTYPE_EXTERN_LEVEL\r\n#define XCHAL_INT6_TYPE \tXTHAL_INTTYPE_TIMER\r\n#define XCHAL_INT7_TYPE \tXTHAL_INTTYPE_SOFTWARE\r\n#define XCHAL_INT8_TYPE \tXTHAL_INTTYPE_EXTERN_EDGE\r\n#define XCHAL_INT9_TYPE \tXTHAL_INTTYPE_EXTERN_EDGE\r\n#define XCHAL_INT10_TYPE \tXTHAL_INTTYPE_EXTERN_EDGE\r\n#define XCHAL_INT11_TYPE \tXTHAL_INTTYPE_EXTERN_EDGE\r\n#define XCHAL_INT12_TYPE \tXTHAL_INTTYPE_EXTERN_EDGE\r\n#define XCHAL_INT13_TYPE \tXTHAL_INTTYPE_EXTERN_EDGE\r\n#define XCHAL_INT14_TYPE \tXTHAL_INTTYPE_NMI\r\n\r\n/*  Masks of interrupts for each type of interrupt:  */\r\n#define XCHAL_INTTYPE_MASK_UNCONFIGURED\t0xFFFF8000\r\n#define XCHAL_INTTYPE_MASK_SOFTWARE\t0x00000080\r\n#define XCHAL_INTTYPE_MASK_EXTERN_EDGE\t0x00003F00\r\n#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL\t0x0000003F\r\n#define XCHAL_INTTYPE_MASK_TIMER\t0x00000040\r\n#define XCHAL_INTTYPE_MASK_NMI\t\t0x00004000\r\n#define XCHAL_INTTYPE_MASK_WRITE_ERROR\t0x00000000\r\n\r\n/*  Interrupt numbers assigned to specific interrupt sources:  */\r\n#define XCHAL_TIMER0_INTERRUPT\t\t6\t/* CCOMPARE0 */\r\n#define XCHAL_TIMER1_INTERRUPT\t\tXTHAL_TIMER_UNCONFIGURED\r\n#define XCHAL_TIMER2_INTERRUPT\t\tXTHAL_TIMER_UNCONFIGURED\r\n#define XCHAL_TIMER3_INTERRUPT\t\tXTHAL_TIMER_UNCONFIGURED\r\n#define XCHAL_NMI_INTERRUPT\t\t14\t/* non-maskable interrupt */\r\n\r\n/*  Interrupt numbers for levels at which only one interrupt is configured:  */\r\n#define XCHAL_INTLEVEL3_NUM\t\t14\r\n/*  (There are many interrupts each at level(s) 1.)  */\r\n\r\n\r\n/*\r\n *  External interrupt vectors/levels.\r\n *  These macros describe how Xtensa processor interrupt numbers\r\n *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers)\r\n *  map to external BInterrupt<n> pins, for those interrupts\r\n *  configured as external (level-triggered, edge-triggered, or NMI).\r\n *  See the Xtensa processor databook for more details.\r\n */\r\n\r\n/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */\r\n#define XCHAL_EXTINT0_NUM\t\t0\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT1_NUM\t\t1\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT2_NUM\t\t2\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT3_NUM\t\t3\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT4_NUM\t\t4\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT5_NUM\t\t5\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT6_NUM\t\t8\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT7_NUM\t\t9\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT8_NUM\t\t10\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT9_NUM\t\t11\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT10_NUM\t\t12\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT11_NUM\t\t13\t/* (intlevel 1) */\r\n#define XCHAL_EXTINT12_NUM\t\t14\t/* (intlevel 3) */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tEXCEPTIONS and VECTORS\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_XEA_VERSION\t\t2\t/* Xtensa Exception Architecture\r\n\t\t\t\t\t\t   number: 1 == XEA1 (old)\r\n\t\t\t\t\t\t\t   2 == XEA2 (new)\r\n\t\t\t\t\t\t\t   0 == XEAX (extern) */\r\n#define XCHAL_HAVE_XEA1\t\t\t0\t/* Exception Architecture 1 */\r\n#define XCHAL_HAVE_XEA2\t\t\t1\t/* Exception Architecture 2 */\r\n#define XCHAL_HAVE_XEAX\t\t\t0\t/* External Exception Arch. */\r\n#define XCHAL_HAVE_EXCEPTIONS\t\t1\t/* exception option */\r\n#define XCHAL_HAVE_MEM_ECC_PARITY\t0\t/* local memory ECC/parity */\r\n#define XCHAL_HAVE_VECTOR_SELECT\t1\t/* relocatable vectors */\r\n#define XCHAL_HAVE_VECBASE\t\t1\t/* relocatable vectors */\r\n#define XCHAL_VECBASE_RESET_VADDR\t0x40000000  /* VECBASE reset value */\r\n#define XCHAL_VECBASE_RESET_PADDR\t0x40000000\r\n#define XCHAL_RESET_VECBASE_OVERLAP\t0\r\n\r\n#define XCHAL_RESET_VECTOR0_VADDR\t0x50000000\r\n#define XCHAL_RESET_VECTOR0_PADDR\t0x50000000\r\n#define XCHAL_RESET_VECTOR1_VADDR\t0x40000080\r\n#define XCHAL_RESET_VECTOR1_PADDR\t0x40000080\r\n#define XCHAL_RESET_VECTOR_VADDR\t0x50000000\r\n#define XCHAL_RESET_VECTOR_PADDR\t0x50000000\r\n#define XCHAL_USER_VECOFS\t\t0x00000050\r\n#define XCHAL_USER_VECTOR_VADDR\t\t0x40000050\r\n#define XCHAL_USER_VECTOR_PADDR\t\t0x40000050\r\n#define XCHAL_KERNEL_VECOFS\t\t0x00000030\r\n#define XCHAL_KERNEL_VECTOR_VADDR\t0x40000030\r\n#define XCHAL_KERNEL_VECTOR_PADDR\t0x40000030\r\n#define XCHAL_DOUBLEEXC_VECOFS\t\t0x00000070\r\n#define XCHAL_DOUBLEEXC_VECTOR_VADDR\t0x40000070\r\n#define XCHAL_DOUBLEEXC_VECTOR_PADDR\t0x40000070\r\n#define XCHAL_INTLEVEL2_VECOFS\t\t0x00000010\r\n#define XCHAL_INTLEVEL2_VECTOR_VADDR\t0x40000010\r\n#define XCHAL_INTLEVEL2_VECTOR_PADDR\t0x40000010\r\n#define XCHAL_DEBUG_VECOFS\t\tXCHAL_INTLEVEL2_VECOFS\r\n#define XCHAL_DEBUG_VECTOR_VADDR\tXCHAL_INTLEVEL2_VECTOR_VADDR\r\n#define XCHAL_DEBUG_VECTOR_PADDR\tXCHAL_INTLEVEL2_VECTOR_PADDR\r\n#define XCHAL_NMI_VECOFS\t\t0x00000020\r\n#define XCHAL_NMI_VECTOR_VADDR\t\t0x40000020\r\n#define XCHAL_NMI_VECTOR_PADDR\t\t0x40000020\r\n#define XCHAL_INTLEVEL3_VECOFS\t\tXCHAL_NMI_VECOFS\r\n#define XCHAL_INTLEVEL3_VECTOR_VADDR\tXCHAL_NMI_VECTOR_VADDR\r\n#define XCHAL_INTLEVEL3_VECTOR_PADDR\tXCHAL_NMI_VECTOR_PADDR\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tDEBUG\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_HAVE_OCD\t\t\t1\t/* OnChipDebug option */\r\n#define XCHAL_NUM_IBREAK\t\t1\t/* number of IBREAKn regs */\r\n#define XCHAL_NUM_DBREAK\t\t1\t/* number of DBREAKn regs */\r\n#define XCHAL_HAVE_OCD_DIR_ARRAY\t0\t/* faster OCD option */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tMMU\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  See core-matmap.h header file for more details.  */\r\n\r\n#define XCHAL_HAVE_TLBS\t\t\t1\t/* inverse of HAVE_CACHEATTR */\r\n#define XCHAL_HAVE_SPANNING_WAY\t\t1\t/* one way maps I+D 4GB vaddr */\r\n#define XCHAL_SPANNING_WAY\t\t0\t/* TLB spanning way number */\r\n#define XCHAL_HAVE_IDENTITY_MAP\t\t1\t/* vaddr == paddr always */\r\n#define XCHAL_HAVE_CACHEATTR\t\t0\t/* CACHEATTR register present */\r\n#define XCHAL_HAVE_MIMIC_CACHEATTR\t1\t/* region protection */\r\n#define XCHAL_HAVE_XLT_CACHEATTR\t0\t/* region prot. w/translation */\r\n#define XCHAL_HAVE_PTP_MMU\t\t0\t/* full MMU (with page table\r\n\t\t\t\t\t\t   [autorefill] and protection)\r\n\t\t\t\t\t\t   usable for an MMU-based OS */\r\n/*  If none of the above last 4 are set, it's a custom TLB configuration.  */\r\n\r\n#define XCHAL_MMU_ASID_BITS\t\t0\t/* number of bits in ASIDs */\r\n#define XCHAL_MMU_RINGS\t\t\t1\t/* number of rings (1..4) */\r\n#define XCHAL_MMU_RING_BITS\t\t0\t/* num of bits in RING field */\r\n\r\n#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */\r\n\r\n\r\n#endif /* _XTENSA_CORE_CONFIGURATION_H */\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/config/core-matmap.h",
    "content": "/* \r\n * xtensa/config/core-matmap.h -- Memory access and translation mapping\r\n *\tparameters (CHAL) of the Xtensa processor core configuration.\r\n *\r\n *  If you are using Xtensa Tools, see <xtensa/config/core.h> (which includes\r\n *  this file) for more details.\r\n *\r\n *  In the Xtensa processor products released to date, all parameters\r\n *  defined in this file are derivable (at least in theory) from\r\n *  information contained in the core-isa.h header file.\r\n *  In particular, the following core configuration parameters are relevant:\r\n *\tXCHAL_HAVE_CACHEATTR\r\n *\tXCHAL_HAVE_MIMIC_CACHEATTR\r\n *\tXCHAL_HAVE_XLT_CACHEATTR\r\n *\tXCHAL_HAVE_PTP_MMU\r\n *\tXCHAL_ITLB_ARF_ENTRIES_LOG2\r\n *\tXCHAL_DTLB_ARF_ENTRIES_LOG2\r\n *\tXCHAL_DCACHE_IS_WRITEBACK\r\n *\tXCHAL_ICACHE_SIZE\t\t(presence of I-cache)\r\n *\tXCHAL_DCACHE_SIZE\t\t(presence of D-cache)\r\n *\tXCHAL_HW_VERSION_MAJOR\r\n *\tXCHAL_HW_VERSION_MINOR\r\n */\r\n\r\n/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */\r\n\r\n\r\n#ifndef XTENSA_CONFIG_CORE_MATMAP_H\r\n#define XTENSA_CONFIG_CORE_MATMAP_H\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tCACHE (MEMORY ACCESS) ATTRIBUTES\r\n  ----------------------------------------------------------------------*/\r\n\r\n\r\n/*  Cache Attribute encodings -- lists of access modes for each cache attribute:  */\r\n#define XCHAL_FCA_LIST\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_FAM_EXCEPTION\r\n#define XCHAL_LCA_LIST\t\tXTHAL_LAM_BYPASSG\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_BYPASSG\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_BYPASSG\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_BYPASSG\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_BYPASSG\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_BYPASSG\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_LAM_EXCEPTION\r\n#define XCHAL_SCA_LIST\t\tXTHAL_SAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_BYPASS\tXCHAL_SEP \\\r\n\t\t\t\tXTHAL_SAM_EXCEPTION\r\n\r\n\r\n/*\r\n *  Specific encoded cache attribute values of general interest.\r\n *  If a specific cache mode is not available, the closest available\r\n *  one is returned instead (eg. writethru instead of writeback,\r\n *  bypass instead of writethru).\r\n */\r\n#define XCHAL_CA_BYPASS  \t\t2\t/* cache disabled (bypassed) mode */\r\n#define XCHAL_CA_WRITETHRU\t\t2\t/* cache enabled (write-through) mode */\r\n#define XCHAL_CA_WRITEBACK\t\t2\t/* cache enabled (write-back) mode */\r\n#define XCHAL_CA_WRITEBACK_NOALLOC\t2\t/* cache enabled (write-back no-allocate) mode */\r\n#define XCHAL_CA_BYPASS_RW  \t\t0\t/* cache disabled (bypassed) mode (no exec) */\r\n#define XCHAL_CA_WRITETHRU_RW\t\t0\t/* cache enabled (write-through) mode (no exec) */\r\n#define XCHAL_CA_WRITEBACK_RW\t\t0\t/* cache enabled (write-back) mode (no exec) */\r\n#define XCHAL_CA_WRITEBACK_NOALLOC_RW\t0\t/* cache enabled (write-back no-allocate) mode (no exec) */\r\n#define XCHAL_CA_ILLEGAL\t\t15\t/* no access allowed (all cause exceptions) mode */\r\n#define XCHAL_CA_ISOLATE\t\t0\t/* cache isolate (accesses go to cache not memory) mode */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tMMU\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*\r\n *  General notes on MMU parameters.\r\n *\r\n *  Terminology:\r\n *\tASID = address-space ID (acts as an \"extension\" of virtual addresses)\r\n *\tVPN  = virtual page number\r\n *\tPPN  = physical page number\r\n *\tCA   = encoded cache attribute (access modes)\r\n *\tTLB  = translation look-aside buffer (term is stretched somewhat here)\r\n *\tI    = instruction (fetch accesses)\r\n *\tD    = data (load and store accesses)\r\n *\tway  = each TLB (ITLB and DTLB) consists of a number of \"ways\"\r\n *\t\tthat simultaneously match the virtual address of an access;\r\n *\t\ta TLB successfully translates a virtual address if exactly\r\n *\t\tone way matches the vaddr; if none match, it is a miss;\r\n *\t\tif multiple match, one gets a \"multihit\" exception;\r\n *\t\teach way can be independently configured in terms of number of\r\n *\t\tentries, page sizes, which fields are writable or constant, etc.\r\n *\tset  = group of contiguous ways with exactly identical parameters\r\n *\tARF  = auto-refill; hardware services a 1st-level miss by loading a PTE\r\n *\t\tfrom the page table and storing it in one of the auto-refill ways;\r\n *\t\tif this PTE load also misses, a miss exception is posted for s/w.\r\n *\tmin-wired = a \"min-wired\" way can be used to map a single (minimum-sized)\r\n * \t\tpage arbitrarily under program control; it has a single entry,\r\n *\t\tis non-auto-refill (some other way(s) must be auto-refill),\r\n *\t\tall its fields (VPN, PPN, ASID, CA) are all writable, and it\r\n *\t\tsupports the XCHAL_MMU_MIN_PTE_PAGE_SIZE page size (a current\r\n *\t\trestriction is that this be the only page size it supports).\r\n *\r\n *  TLB way entries are virtually indexed.\r\n *  TLB ways that support multiple page sizes:\r\n *\t- must have all writable VPN and PPN fields;\r\n *\t- can only use one page size at any given time (eg. setup at startup),\r\n *\t  selected by the respective ITLBCFG or DTLBCFG special register,\r\n *\t  whose bits n*4+3 .. n*4 index the list of page sizes for way n\r\n *\t  (XCHAL_xTLB_SETm_PAGESZ_LOG2_LIST for set m corresponding to way n);\r\n *\t  this list may be sparse for auto-refill ways because auto-refill\r\n *\t  ways have independent lists of supported page sizes sharing a\r\n *\t  common encoding with PTE entries; the encoding is the index into\r\n *\t  this list; unsupported sizes for a given way are zero in the list;\r\n *\t  selecting unsupported sizes results in undefined hardware behaviour;\r\n *\t- is only possible for ways 0 thru 7 (due to ITLBCFG/DTLBCFG definition).\r\n */\r\n\r\n#define XCHAL_MMU_ASID_INVALID\t\t0\t/* ASID value indicating invalid address space */\r\n#define XCHAL_MMU_ASID_KERNEL\t\t0\t/* ASID value indicating kernel (ring 0) address space */\r\n#define XCHAL_MMU_SR_BITS\t\t0\t/* number of size-restriction bits supported */\r\n#define XCHAL_MMU_CA_BITS\t\t4\t/* number of bits needed to hold cache attribute encoding */\r\n#define XCHAL_MMU_MAX_PTE_PAGE_SIZE\t29\t/* max page size in a PTE structure (log2) */\r\n#define XCHAL_MMU_MIN_PTE_PAGE_SIZE\t29\t/* min page size in a PTE structure (log2) */\r\n\r\n\r\n/***  Instruction TLB:  ***/\r\n\r\n#define XCHAL_ITLB_WAY_BITS\t\t0\t/* number of bits holding the ways */\r\n#define XCHAL_ITLB_WAYS\t\t\t1\t/* number of ways (n-way set-associative TLB) */\r\n#define XCHAL_ITLB_ARF_WAYS\t\t0\t/* number of auto-refill ways */\r\n#define XCHAL_ITLB_SETS\t\t\t1\t/* number of sets (groups of ways with identical settings) */\r\n\r\n/*  Way set to which each way belongs:  */\r\n#define XCHAL_ITLB_WAY0_SET\t\t0\r\n\r\n/*  Ways sets that are used by hardware auto-refill (ARF):  */\r\n#define XCHAL_ITLB_ARF_SETS\t\t0\t/* number of auto-refill sets */\r\n\r\n/*  Way sets that are \"min-wired\" (see terminology comment above):  */\r\n#define XCHAL_ITLB_MINWIRED_SETS\t0\t/* number of \"min-wired\" sets */\r\n\r\n\r\n/*  ITLB way set 0 (group of ways 0 thru 0):  */\r\n#define XCHAL_ITLB_SET0_WAY\t\t\t0\t/* index of first way in this way set */\r\n#define XCHAL_ITLB_SET0_WAYS\t\t\t1\t/* number of (contiguous) ways in this way set */\r\n#define XCHAL_ITLB_SET0_ENTRIES_LOG2\t\t3\t/* log2(number of entries in this way) */\r\n#define XCHAL_ITLB_SET0_ENTRIES\t\t\t8\t/* number of entries in this way (always a power of 2) */\r\n#define XCHAL_ITLB_SET0_ARF\t\t\t0\t/* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */\r\n#define XCHAL_ITLB_SET0_PAGESIZES\t\t1\t/* number of supported page sizes in this way */\r\n#define XCHAL_ITLB_SET0_PAGESZ_BITS\t\t0\t/* number of bits to encode the page size */\r\n#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MIN\t\t29\t/* log2(minimum supported page size) */\r\n#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MAX\t\t29\t/* log2(maximum supported page size) */\r\n#define XCHAL_ITLB_SET0_PAGESZ_LOG2_LIST\t29\t/* list of log2(page size)s, separated by XCHAL_SEP;\r\n\t\t\t\t\t\t\t   2^PAGESZ_BITS entries in list, unsupported entries are zero */\r\n#define XCHAL_ITLB_SET0_ASID_CONSTMASK\t\t0\t/* constant ASID bits; 0 if all writable */\r\n#define XCHAL_ITLB_SET0_VPN_CONSTMASK\t\t0x00000000\t/* constant VPN bits, not including entry index bits; 0 if all writable */\r\n#define XCHAL_ITLB_SET0_PPN_CONSTMASK\t\t0xE0000000\t/* constant PPN bits, including entry index bits; 0 if all writable */\r\n#define XCHAL_ITLB_SET0_CA_CONSTMASK\t\t0\t/* constant CA bits; 0 if all writable */\r\n#define XCHAL_ITLB_SET0_ASID_RESET\t\t0\t/* 1 if ASID reset values defined (and all writable); 0 otherwise */\r\n#define XCHAL_ITLB_SET0_VPN_RESET\t\t0\t/* 1 if VPN reset values defined (and all writable); 0 otherwise */\r\n#define XCHAL_ITLB_SET0_PPN_RESET\t\t0\t/* 1 if PPN reset values defined (and all writable); 0 otherwise */\r\n#define XCHAL_ITLB_SET0_CA_RESET\t\t1\t/* 1 if CA reset values defined (and all writable); 0 otherwise */\r\n/*  Constant VPN values for each entry of ITLB way set 0 (because VPN_CONSTMASK is non-zero):  */\r\n#define XCHAL_ITLB_SET0_E0_VPN_CONST\t\t0x00000000\r\n#define XCHAL_ITLB_SET0_E1_VPN_CONST\t\t0x20000000\r\n#define XCHAL_ITLB_SET0_E2_VPN_CONST\t\t0x40000000\r\n#define XCHAL_ITLB_SET0_E3_VPN_CONST\t\t0x60000000\r\n#define XCHAL_ITLB_SET0_E4_VPN_CONST\t\t0x80000000\r\n#define XCHAL_ITLB_SET0_E5_VPN_CONST\t\t0xA0000000\r\n#define XCHAL_ITLB_SET0_E6_VPN_CONST\t\t0xC0000000\r\n#define XCHAL_ITLB_SET0_E7_VPN_CONST\t\t0xE0000000\r\n/*  Constant PPN values for each entry of ITLB way set 0 (because PPN_CONSTMASK is non-zero):  */\r\n#define XCHAL_ITLB_SET0_E0_PPN_CONST\t\t0x00000000\r\n#define XCHAL_ITLB_SET0_E1_PPN_CONST\t\t0x20000000\r\n#define XCHAL_ITLB_SET0_E2_PPN_CONST\t\t0x40000000\r\n#define XCHAL_ITLB_SET0_E3_PPN_CONST\t\t0x60000000\r\n#define XCHAL_ITLB_SET0_E4_PPN_CONST\t\t0x80000000\r\n#define XCHAL_ITLB_SET0_E5_PPN_CONST\t\t0xA0000000\r\n#define XCHAL_ITLB_SET0_E6_PPN_CONST\t\t0xC0000000\r\n#define XCHAL_ITLB_SET0_E7_PPN_CONST\t\t0xE0000000\r\n/*  Reset CA values for each entry of ITLB way set 0 (because SET0_CA_RESET is non-zero):  */\r\n#define XCHAL_ITLB_SET0_E0_CA_RESET\t\t0x02\r\n#define XCHAL_ITLB_SET0_E1_CA_RESET\t\t0x02\r\n#define XCHAL_ITLB_SET0_E2_CA_RESET\t\t0x02\r\n#define XCHAL_ITLB_SET0_E3_CA_RESET\t\t0x02\r\n#define XCHAL_ITLB_SET0_E4_CA_RESET\t\t0x02\r\n#define XCHAL_ITLB_SET0_E5_CA_RESET\t\t0x02\r\n#define XCHAL_ITLB_SET0_E6_CA_RESET\t\t0x02\r\n#define XCHAL_ITLB_SET0_E7_CA_RESET\t\t0x02\r\n\r\n\r\n/***  Data TLB:  ***/\r\n\r\n#define XCHAL_DTLB_WAY_BITS\t\t0\t/* number of bits holding the ways */\r\n#define XCHAL_DTLB_WAYS\t\t\t1\t/* number of ways (n-way set-associative TLB) */\r\n#define XCHAL_DTLB_ARF_WAYS\t\t0\t/* number of auto-refill ways */\r\n#define XCHAL_DTLB_SETS\t\t\t1\t/* number of sets (groups of ways with identical settings) */\r\n\r\n/*  Way set to which each way belongs:  */\r\n#define XCHAL_DTLB_WAY0_SET\t\t0\r\n\r\n/*  Ways sets that are used by hardware auto-refill (ARF):  */\r\n#define XCHAL_DTLB_ARF_SETS\t\t0\t/* number of auto-refill sets */\r\n\r\n/*  Way sets that are \"min-wired\" (see terminology comment above):  */\r\n#define XCHAL_DTLB_MINWIRED_SETS\t0\t/* number of \"min-wired\" sets */\r\n\r\n\r\n/*  DTLB way set 0 (group of ways 0 thru 0):  */\r\n#define XCHAL_DTLB_SET0_WAY\t\t\t0\t/* index of first way in this way set */\r\n#define XCHAL_DTLB_SET0_WAYS\t\t\t1\t/* number of (contiguous) ways in this way set */\r\n#define XCHAL_DTLB_SET0_ENTRIES_LOG2\t\t3\t/* log2(number of entries in this way) */\r\n#define XCHAL_DTLB_SET0_ENTRIES\t\t\t8\t/* number of entries in this way (always a power of 2) */\r\n#define XCHAL_DTLB_SET0_ARF\t\t\t0\t/* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */\r\n#define XCHAL_DTLB_SET0_PAGESIZES\t\t1\t/* number of supported page sizes in this way */\r\n#define XCHAL_DTLB_SET0_PAGESZ_BITS\t\t0\t/* number of bits to encode the page size */\r\n#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MIN\t\t29\t/* log2(minimum supported page size) */\r\n#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MAX\t\t29\t/* log2(maximum supported page size) */\r\n#define XCHAL_DTLB_SET0_PAGESZ_LOG2_LIST\t29\t/* list of log2(page size)s, separated by XCHAL_SEP;\r\n\t\t\t\t\t\t\t   2^PAGESZ_BITS entries in list, unsupported entries are zero */\r\n#define XCHAL_DTLB_SET0_ASID_CONSTMASK\t\t0\t/* constant ASID bits; 0 if all writable */\r\n#define XCHAL_DTLB_SET0_VPN_CONSTMASK\t\t0x00000000\t/* constant VPN bits, not including entry index bits; 0 if all writable */\r\n#define XCHAL_DTLB_SET0_PPN_CONSTMASK\t\t0xE0000000\t/* constant PPN bits, including entry index bits; 0 if all writable */\r\n#define XCHAL_DTLB_SET0_CA_CONSTMASK\t\t0\t/* constant CA bits; 0 if all writable */\r\n#define XCHAL_DTLB_SET0_ASID_RESET\t\t0\t/* 1 if ASID reset values defined (and all writable); 0 otherwise */\r\n#define XCHAL_DTLB_SET0_VPN_RESET\t\t0\t/* 1 if VPN reset values defined (and all writable); 0 otherwise */\r\n#define XCHAL_DTLB_SET0_PPN_RESET\t\t0\t/* 1 if PPN reset values defined (and all writable); 0 otherwise */\r\n#define XCHAL_DTLB_SET0_CA_RESET\t\t1\t/* 1 if CA reset values defined (and all writable); 0 otherwise */\r\n/*  Constant VPN values for each entry of DTLB way set 0 (because VPN_CONSTMASK is non-zero):  */\r\n#define XCHAL_DTLB_SET0_E0_VPN_CONST\t\t0x00000000\r\n#define XCHAL_DTLB_SET0_E1_VPN_CONST\t\t0x20000000\r\n#define XCHAL_DTLB_SET0_E2_VPN_CONST\t\t0x40000000\r\n#define XCHAL_DTLB_SET0_E3_VPN_CONST\t\t0x60000000\r\n#define XCHAL_DTLB_SET0_E4_VPN_CONST\t\t0x80000000\r\n#define XCHAL_DTLB_SET0_E5_VPN_CONST\t\t0xA0000000\r\n#define XCHAL_DTLB_SET0_E6_VPN_CONST\t\t0xC0000000\r\n#define XCHAL_DTLB_SET0_E7_VPN_CONST\t\t0xE0000000\r\n/*  Constant PPN values for each entry of DTLB way set 0 (because PPN_CONSTMASK is non-zero):  */\r\n#define XCHAL_DTLB_SET0_E0_PPN_CONST\t\t0x00000000\r\n#define XCHAL_DTLB_SET0_E1_PPN_CONST\t\t0x20000000\r\n#define XCHAL_DTLB_SET0_E2_PPN_CONST\t\t0x40000000\r\n#define XCHAL_DTLB_SET0_E3_PPN_CONST\t\t0x60000000\r\n#define XCHAL_DTLB_SET0_E4_PPN_CONST\t\t0x80000000\r\n#define XCHAL_DTLB_SET0_E5_PPN_CONST\t\t0xA0000000\r\n#define XCHAL_DTLB_SET0_E6_PPN_CONST\t\t0xC0000000\r\n#define XCHAL_DTLB_SET0_E7_PPN_CONST\t\t0xE0000000\r\n/*  Reset CA values for each entry of DTLB way set 0 (because SET0_CA_RESET is non-zero):  */\r\n#define XCHAL_DTLB_SET0_E0_CA_RESET\t\t0x02\r\n#define XCHAL_DTLB_SET0_E1_CA_RESET\t\t0x02\r\n#define XCHAL_DTLB_SET0_E2_CA_RESET\t\t0x02\r\n#define XCHAL_DTLB_SET0_E3_CA_RESET\t\t0x02\r\n#define XCHAL_DTLB_SET0_E4_CA_RESET\t\t0x02\r\n#define XCHAL_DTLB_SET0_E5_CA_RESET\t\t0x02\r\n#define XCHAL_DTLB_SET0_E6_CA_RESET\t\t0x02\r\n#define XCHAL_DTLB_SET0_E7_CA_RESET\t\t0x02\r\n\r\n\r\n\r\n\r\n#endif /*XTENSA_CONFIG_CORE_MATMAP_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/config/core.h",
    "content": "/* \r\n * xtensa/config/core.h -- HAL definitions dependent on CORE configuration\r\n *\r\n *  This header file is sometimes referred to as the \"compile-time HAL\" or CHAL.\r\n *  It pulls definitions tailored for a specific Xtensa processor configuration.\r\n *\r\n *  Sources for binaries meant to be configuration-independent generally avoid\r\n *  including this file (they may use the configuration-specific HAL library).\r\n *  It is normal for the HAL library source itself to include this file.\r\n */\r\n\r\n/*\r\n * Copyright (c) 2005-2010 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n\r\n#ifndef XTENSA_CONFIG_CORE_H\r\n#define XTENSA_CONFIG_CORE_H\r\n\r\n/*  CONFIGURATION INDEPENDENT DEFINITIONS:  */\r\n#ifdef __XTENSA__\r\n#include <xtensa/hal.h>\r\n#else\r\n#include \"../hal.h\"\r\n#endif\r\n\r\n/*  CONFIGURATION SPECIFIC DEFINITIONS:  */\r\n#ifdef __XTENSA__\r\n#include <xtensa/config/core-isa.h>\r\n#include <xtensa/config/core-matmap.h>\r\n#include <xtensa/config/tie.h>\r\n#else\r\n#include \"core-isa.h\"\r\n#include \"core-matmap.h\"\r\n#include \"tie.h\"\r\n#endif\r\n\r\n#if defined (_ASMLANGUAGE) || defined (__ASSEMBLER__)\r\n#ifdef __XTENSA__\r\n#include <xtensa/config/tie-asm.h>\r\n#else\r\n#include \"tie-asm.h\"\r\n#endif\r\n#endif /*_ASMLANGUAGE or __ASSEMBLER__*/\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tGENERAL\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*\r\n *  Separators for macros that expand into arrays.\r\n *  These can be predefined by files that #include this one,\r\n *  when different separators are required.\r\n */\r\n/*  Element separator for macros that expand into 1-dimensional arrays:  */\r\n#ifndef XCHAL_SEP\r\n#define XCHAL_SEP\t\t\t,\r\n#endif\r\n/*  Array separator for macros that expand into 2-dimensional arrays:  */\r\n#ifndef XCHAL_SEP2\r\n#define XCHAL_SEP2\t\t\t},{\r\n#endif\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tISA\r\n  ----------------------------------------------------------------------*/\r\n\r\n#if XCHAL_HAVE_BE\r\n# define XCHAL_HAVE_LE\t\t\t0\r\n# define XCHAL_MEMORY_ORDER\t\tXTHAL_BIGENDIAN\r\n#else\r\n# define XCHAL_HAVE_LE\t\t\t1\r\n# define XCHAL_MEMORY_ORDER\t\tXTHAL_LITTLEENDIAN\r\n#endif\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tINTERRUPTS\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  Indexing macros:  */\r\n#define _XCHAL_INTLEVEL_MASK(n)\t\tXCHAL_INTLEVEL ## n ## _MASK\r\n#define XCHAL_INTLEVEL_MASK(n)\t\t_XCHAL_INTLEVEL_MASK(n)\t\t/* n = 0 .. 15 */\r\n#define _XCHAL_INTLEVEL_ANDBELOWMASK(n)\tXCHAL_INTLEVEL ## n ## _ANDBELOW_MASK\r\n#define XCHAL_INTLEVEL_ANDBELOW_MASK(n)\t_XCHAL_INTLEVEL_ANDBELOWMASK(n)\t/* n = 0 .. 15 */\r\n#define _XCHAL_INTLEVEL_NUM(n)\t\tXCHAL_INTLEVEL ## n ## _NUM\r\n#define XCHAL_INTLEVEL_NUM(n)\t\t_XCHAL_INTLEVEL_NUM(n)\t\t/* n = 0 .. 15 */\r\n#define _XCHAL_INT_LEVEL(n)\t\tXCHAL_INT ## n ## _LEVEL\r\n#define XCHAL_INT_LEVEL(n)\t\t_XCHAL_INT_LEVEL(n)\t\t/* n = 0 .. 31 */\r\n#define _XCHAL_INT_TYPE(n)\t\tXCHAL_INT ## n ## _TYPE\r\n#define XCHAL_INT_TYPE(n)\t\t_XCHAL_INT_TYPE(n)\t\t/* n = 0 .. 31 */\r\n#define _XCHAL_TIMER_INTERRUPT(n)\tXCHAL_TIMER ## n ## _INTERRUPT\r\n#define XCHAL_TIMER_INTERRUPT(n)\t_XCHAL_TIMER_INTERRUPT(n)\t/* n = 0 .. 3 */\r\n\r\n\r\n#define XCHAL_HAVE_HIGHLEVEL_INTERRUPTS\tXCHAL_HAVE_HIGHPRI_INTERRUPTS\r\n#define XCHAL_NUM_LOWPRI_LEVELS\t\t1\t\t\t/* number of low-priority interrupt levels (always 1) */\r\n#define XCHAL_FIRST_HIGHPRI_LEVEL\t(XCHAL_NUM_LOWPRI_LEVELS+1)\t/* level of first high-priority interrupt (always 2) */\r\n/*  Note:  1 <= LOWPRI_LEVELS <= EXCM_LEVEL < DEBUGLEVEL <= NUM_INTLEVELS < NMILEVEL <= 15  */\r\n\r\n/*  These values are constant for existing Xtensa processor implementations:  */\r\n#define XCHAL_INTLEVEL0_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL8_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL9_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL10_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL11_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL12_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL13_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL14_MASK\t\t0x00000000\r\n#define XCHAL_INTLEVEL15_MASK\t\t0x00000000\r\n\r\n/*  Array of masks of interrupts at each interrupt level:  */\r\n#define XCHAL_INTLEVEL_MASKS\t\tXCHAL_INTLEVEL0_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL1_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL2_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL3_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL4_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL5_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL6_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL7_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL8_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL9_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL10_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL11_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL12_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL13_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL14_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL15_MASK\r\n\r\n/*  These values are constant for existing Xtensa processor implementations:  */\r\n#define XCHAL_INTLEVEL0_ANDBELOW_MASK\t0x00000000\r\n#define XCHAL_INTLEVEL8_ANDBELOW_MASK\tXCHAL_INTLEVEL7_ANDBELOW_MASK\r\n#define XCHAL_INTLEVEL9_ANDBELOW_MASK\tXCHAL_INTLEVEL7_ANDBELOW_MASK\r\n#define XCHAL_INTLEVEL10_ANDBELOW_MASK\tXCHAL_INTLEVEL7_ANDBELOW_MASK\r\n#define XCHAL_INTLEVEL11_ANDBELOW_MASK\tXCHAL_INTLEVEL7_ANDBELOW_MASK\r\n#define XCHAL_INTLEVEL12_ANDBELOW_MASK\tXCHAL_INTLEVEL7_ANDBELOW_MASK\r\n#define XCHAL_INTLEVEL13_ANDBELOW_MASK\tXCHAL_INTLEVEL7_ANDBELOW_MASK\r\n#define XCHAL_INTLEVEL14_ANDBELOW_MASK\tXCHAL_INTLEVEL7_ANDBELOW_MASK\r\n#define XCHAL_INTLEVEL15_ANDBELOW_MASK\tXCHAL_INTLEVEL7_ANDBELOW_MASK\r\n\r\n/*  Mask of all low-priority interrupts:  */\r\n#define XCHAL_LOWPRI_MASK\t\tXCHAL_INTLEVEL1_ANDBELOW_MASK\r\n\r\n/*  Mask of all interrupts masked by PS.EXCM (or CEXCM):  */\r\n#define XCHAL_EXCM_MASK\t\t\tXCHAL_INTLEVEL_ANDBELOW_MASK(XCHAL_EXCM_LEVEL)\r\n\r\n/*  Array of masks of interrupts at each range 1..n of interrupt levels:  */\r\n#define XCHAL_INTLEVEL_ANDBELOW_MASKS\tXCHAL_INTLEVEL0_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL1_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL2_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL3_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL4_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL5_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL6_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL7_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL8_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL9_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL10_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL11_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL12_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL13_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL14_ANDBELOW_MASK \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTLEVEL15_ANDBELOW_MASK\r\n\r\n#if 0 /*XCHAL_HAVE_NMI*/\r\n/*  NMI \"interrupt level\" (for use with EXCSAVE_n, EPS_n, EPC_n, RFI n):  */\r\n# define XCHAL_NMILEVEL\t\t(XCHAL_NUM_INTLEVELS+1)\r\n#endif\r\n\r\n/*  Array of levels of each possible interrupt:  */\r\n#define XCHAL_INT_LEVELS\t\tXCHAL_INT0_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT1_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT2_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT3_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT4_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT5_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT6_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT7_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT8_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT9_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT10_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT11_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT12_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT13_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT14_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT15_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT16_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT17_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT18_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT19_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT20_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT21_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT22_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT23_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT24_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT25_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT26_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT27_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT28_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT29_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT30_LEVEL \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT31_LEVEL\r\n\r\n/*  Array of types of each possible interrupt:  */\r\n#define XCHAL_INT_TYPES\t\t\tXCHAL_INT0_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT1_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT2_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT3_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT4_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT5_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT6_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT7_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT8_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT9_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT10_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT11_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT12_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT13_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT14_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT15_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT16_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT17_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT18_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT19_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT20_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT21_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT22_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT23_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT24_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT25_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT26_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT27_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT28_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT29_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT30_TYPE \\\r\n\t\t\tXCHAL_SEP\tXCHAL_INT31_TYPE\r\n\r\n/*  Array of masks of interrupts for each type of interrupt:  */\r\n#define XCHAL_INTTYPE_MASKS\t\tXCHAL_INTTYPE_MASK_UNCONFIGURED\t\\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTTYPE_MASK_SOFTWARE\t\\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTTYPE_MASK_EXTERN_EDGE\t\\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTTYPE_MASK_EXTERN_LEVEL\t\\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTTYPE_MASK_TIMER\t\\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTTYPE_MASK_NMI\t\t\\\r\n\t\t\tXCHAL_SEP\tXCHAL_INTTYPE_MASK_WRITE_ERROR\r\n\r\n/*  Interrupts that can be cleared using the INTCLEAR special register:  */\r\n#define XCHAL_INTCLEARABLE_MASK\t(XCHAL_INTTYPE_MASK_SOFTWARE+XCHAL_INTTYPE_MASK_EXTERN_EDGE+XCHAL_INTTYPE_MASK_WRITE_ERROR)\r\n/*  Interrupts that can be triggered using the INTSET special register:  */\r\n#define XCHAL_INTSETTABLE_MASK\tXCHAL_INTTYPE_MASK_SOFTWARE\r\n\r\n/*  Array of interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3):  */\r\n#define XCHAL_TIMER_INTERRUPTS\t\tXCHAL_TIMER0_INTERRUPT \\\r\n\t\t\tXCHAL_SEP\tXCHAL_TIMER1_INTERRUPT \\\r\n\t\t\tXCHAL_SEP\tXCHAL_TIMER2_INTERRUPT \\\r\n\t\t\tXCHAL_SEP\tXCHAL_TIMER3_INTERRUPT\r\n\r\n\r\n\r\n/*  For backward compatibility and for the array macros, define macros for\r\n *  each unconfigured interrupt number (unfortunately, the value of\r\n *  XTHAL_INTTYPE_UNCONFIGURED is not zero):  */\r\n#if XCHAL_NUM_INTERRUPTS == 0\r\n# define XCHAL_INT0_LEVEL\t\t0\r\n# define XCHAL_INT0_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 1\r\n# define XCHAL_INT1_LEVEL\t\t0\r\n# define XCHAL_INT1_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 2\r\n# define XCHAL_INT2_LEVEL\t\t0\r\n# define XCHAL_INT2_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 3\r\n# define XCHAL_INT3_LEVEL\t\t0\r\n# define XCHAL_INT3_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 4\r\n# define XCHAL_INT4_LEVEL\t\t0\r\n# define XCHAL_INT4_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 5\r\n# define XCHAL_INT5_LEVEL\t\t0\r\n# define XCHAL_INT5_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 6\r\n# define XCHAL_INT6_LEVEL\t\t0\r\n# define XCHAL_INT6_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 7\r\n# define XCHAL_INT7_LEVEL\t\t0\r\n# define XCHAL_INT7_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 8\r\n# define XCHAL_INT8_LEVEL\t\t0\r\n# define XCHAL_INT8_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 9\r\n# define XCHAL_INT9_LEVEL\t\t0\r\n# define XCHAL_INT9_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 10\r\n# define XCHAL_INT10_LEVEL\t\t0\r\n# define XCHAL_INT10_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 11\r\n# define XCHAL_INT11_LEVEL\t\t0\r\n# define XCHAL_INT11_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 12\r\n# define XCHAL_INT12_LEVEL\t\t0\r\n# define XCHAL_INT12_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 13\r\n# define XCHAL_INT13_LEVEL\t\t0\r\n# define XCHAL_INT13_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 14\r\n# define XCHAL_INT14_LEVEL\t\t0\r\n# define XCHAL_INT14_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 15\r\n# define XCHAL_INT15_LEVEL\t\t0\r\n# define XCHAL_INT15_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 16\r\n# define XCHAL_INT16_LEVEL\t\t0\r\n# define XCHAL_INT16_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 17\r\n# define XCHAL_INT17_LEVEL\t\t0\r\n# define XCHAL_INT17_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 18\r\n# define XCHAL_INT18_LEVEL\t\t0\r\n# define XCHAL_INT18_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 19\r\n# define XCHAL_INT19_LEVEL\t\t0\r\n# define XCHAL_INT19_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 20\r\n# define XCHAL_INT20_LEVEL\t\t0\r\n# define XCHAL_INT20_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 21\r\n# define XCHAL_INT21_LEVEL\t\t0\r\n# define XCHAL_INT21_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 22\r\n# define XCHAL_INT22_LEVEL\t\t0\r\n# define XCHAL_INT22_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 23\r\n# define XCHAL_INT23_LEVEL\t\t0\r\n# define XCHAL_INT23_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 24\r\n# define XCHAL_INT24_LEVEL\t\t0\r\n# define XCHAL_INT24_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 25\r\n# define XCHAL_INT25_LEVEL\t\t0\r\n# define XCHAL_INT25_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 26\r\n# define XCHAL_INT26_LEVEL\t\t0\r\n# define XCHAL_INT26_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 27\r\n# define XCHAL_INT27_LEVEL\t\t0\r\n# define XCHAL_INT27_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 28\r\n# define XCHAL_INT28_LEVEL\t\t0\r\n# define XCHAL_INT28_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 29\r\n# define XCHAL_INT29_LEVEL\t\t0\r\n# define XCHAL_INT29_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 30\r\n# define XCHAL_INT30_LEVEL\t\t0\r\n# define XCHAL_INT30_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n#if XCHAL_NUM_INTERRUPTS <= 31\r\n# define XCHAL_INT31_LEVEL\t\t0\r\n# define XCHAL_INT31_TYPE\t\tXTHAL_INTTYPE_UNCONFIGURED\r\n#endif\r\n\r\n\r\n/*\r\n *  Masks and levels corresponding to each *external* interrupt.\r\n */\r\n\r\n#define XCHAL_EXTINT0_MASK\t\t(1 << XCHAL_EXTINT0_NUM)\r\n#define XCHAL_EXTINT0_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT0_NUM)\r\n#define XCHAL_EXTINT1_MASK\t\t(1 << XCHAL_EXTINT1_NUM)\r\n#define XCHAL_EXTINT1_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT1_NUM)\r\n#define XCHAL_EXTINT2_MASK\t\t(1 << XCHAL_EXTINT2_NUM)\r\n#define XCHAL_EXTINT2_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT2_NUM)\r\n#define XCHAL_EXTINT3_MASK\t\t(1 << XCHAL_EXTINT3_NUM)\r\n#define XCHAL_EXTINT3_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT3_NUM)\r\n#define XCHAL_EXTINT4_MASK\t\t(1 << XCHAL_EXTINT4_NUM)\r\n#define XCHAL_EXTINT4_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT4_NUM)\r\n#define XCHAL_EXTINT5_MASK\t\t(1 << XCHAL_EXTINT5_NUM)\r\n#define XCHAL_EXTINT5_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT5_NUM)\r\n#define XCHAL_EXTINT6_MASK\t\t(1 << XCHAL_EXTINT6_NUM)\r\n#define XCHAL_EXTINT6_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT6_NUM)\r\n#define XCHAL_EXTINT7_MASK\t\t(1 << XCHAL_EXTINT7_NUM)\r\n#define XCHAL_EXTINT7_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT7_NUM)\r\n#define XCHAL_EXTINT8_MASK\t\t(1 << XCHAL_EXTINT8_NUM)\r\n#define XCHAL_EXTINT8_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT8_NUM)\r\n#define XCHAL_EXTINT9_MASK\t\t(1 << XCHAL_EXTINT9_NUM)\r\n#define XCHAL_EXTINT9_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT9_NUM)\r\n#define XCHAL_EXTINT10_MASK\t\t(1 << XCHAL_EXTINT10_NUM)\r\n#define XCHAL_EXTINT10_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT10_NUM)\r\n#define XCHAL_EXTINT11_MASK\t\t(1 << XCHAL_EXTINT11_NUM)\r\n#define XCHAL_EXTINT11_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT11_NUM)\r\n#define XCHAL_EXTINT12_MASK\t\t(1 << XCHAL_EXTINT12_NUM)\r\n#define XCHAL_EXTINT12_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT12_NUM)\r\n#define XCHAL_EXTINT13_MASK\t\t(1 << XCHAL_EXTINT13_NUM)\r\n#define XCHAL_EXTINT13_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT13_NUM)\r\n#define XCHAL_EXTINT14_MASK\t\t(1 << XCHAL_EXTINT14_NUM)\r\n#define XCHAL_EXTINT14_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT14_NUM)\r\n#define XCHAL_EXTINT15_MASK\t\t(1 << XCHAL_EXTINT15_NUM)\r\n#define XCHAL_EXTINT15_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT15_NUM)\r\n#define XCHAL_EXTINT16_MASK\t\t(1 << XCHAL_EXTINT16_NUM)\r\n#define XCHAL_EXTINT16_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT16_NUM)\r\n#define XCHAL_EXTINT17_MASK\t\t(1 << XCHAL_EXTINT17_NUM)\r\n#define XCHAL_EXTINT17_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT17_NUM)\r\n#define XCHAL_EXTINT18_MASK\t\t(1 << XCHAL_EXTINT18_NUM)\r\n#define XCHAL_EXTINT18_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT18_NUM)\r\n#define XCHAL_EXTINT19_MASK\t\t(1 << XCHAL_EXTINT19_NUM)\r\n#define XCHAL_EXTINT19_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT19_NUM)\r\n#define XCHAL_EXTINT20_MASK\t\t(1 << XCHAL_EXTINT20_NUM)\r\n#define XCHAL_EXTINT20_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT20_NUM)\r\n#define XCHAL_EXTINT21_MASK\t\t(1 << XCHAL_EXTINT21_NUM)\r\n#define XCHAL_EXTINT21_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT21_NUM)\r\n#define XCHAL_EXTINT22_MASK\t\t(1 << XCHAL_EXTINT22_NUM)\r\n#define XCHAL_EXTINT22_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT22_NUM)\r\n#define XCHAL_EXTINT23_MASK\t\t(1 << XCHAL_EXTINT23_NUM)\r\n#define XCHAL_EXTINT23_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT23_NUM)\r\n#define XCHAL_EXTINT24_MASK\t\t(1 << XCHAL_EXTINT24_NUM)\r\n#define XCHAL_EXTINT24_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT24_NUM)\r\n#define XCHAL_EXTINT25_MASK\t\t(1 << XCHAL_EXTINT25_NUM)\r\n#define XCHAL_EXTINT25_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT25_NUM)\r\n#define XCHAL_EXTINT26_MASK\t\t(1 << XCHAL_EXTINT26_NUM)\r\n#define XCHAL_EXTINT26_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT26_NUM)\r\n#define XCHAL_EXTINT27_MASK\t\t(1 << XCHAL_EXTINT27_NUM)\r\n#define XCHAL_EXTINT27_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT27_NUM)\r\n#define XCHAL_EXTINT28_MASK\t\t(1 << XCHAL_EXTINT28_NUM)\r\n#define XCHAL_EXTINT28_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT28_NUM)\r\n#define XCHAL_EXTINT29_MASK\t\t(1 << XCHAL_EXTINT29_NUM)\r\n#define XCHAL_EXTINT29_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT29_NUM)\r\n#define XCHAL_EXTINT30_MASK\t\t(1 << XCHAL_EXTINT30_NUM)\r\n#define XCHAL_EXTINT30_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT30_NUM)\r\n#define XCHAL_EXTINT31_MASK\t\t(1 << XCHAL_EXTINT31_NUM)\r\n#define XCHAL_EXTINT31_LEVEL\t\tXCHAL_INT_LEVEL(XCHAL_EXTINT31_NUM)\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tEXCEPTIONS and VECTORS\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  For backward compatibility ONLY -- DO NOT USE (will be removed in future release):  */\r\n#define XCHAL_HAVE_OLD_EXC_ARCH\t\tXCHAL_HAVE_XEA1\t/* (DEPRECATED) 1 if old exception architecture (XEA1), 0 otherwise (eg. XEA2) */\r\n#define XCHAL_HAVE_EXCM\t\t\tXCHAL_HAVE_XEA2\t/* (DEPRECATED) 1 if PS.EXCM bit exists (currently equals XCHAL_HAVE_TLBS) */\r\n#ifdef XCHAL_USER_VECTOR_VADDR\r\n#define XCHAL_PROGRAMEXC_VECTOR_VADDR\tXCHAL_USER_VECTOR_VADDR\r\n#define XCHAL_USEREXC_VECTOR_VADDR\tXCHAL_USER_VECTOR_VADDR\r\n#endif\r\n#ifdef XCHAL_USER_VECTOR_PADDR\r\n# define XCHAL_PROGRAMEXC_VECTOR_PADDR\tXCHAL_USER_VECTOR_PADDR\r\n# define XCHAL_USEREXC_VECTOR_PADDR\tXCHAL_USER_VECTOR_PADDR\r\n#endif\r\n#ifdef XCHAL_KERNEL_VECTOR_VADDR\r\n# define XCHAL_STACKEDEXC_VECTOR_VADDR\tXCHAL_KERNEL_VECTOR_VADDR\r\n# define XCHAL_KERNELEXC_VECTOR_VADDR\tXCHAL_KERNEL_VECTOR_VADDR\r\n#endif\r\n#ifdef XCHAL_KERNEL_VECTOR_PADDR\r\n# define XCHAL_STACKEDEXC_VECTOR_PADDR\tXCHAL_KERNEL_VECTOR_PADDR\r\n# define XCHAL_KERNELEXC_VECTOR_PADDR\tXCHAL_KERNEL_VECTOR_PADDR\r\n#endif\r\n\r\n#if 0\r\n#if XCHAL_HAVE_DEBUG\r\n# define XCHAL_DEBUG_VECTOR_VADDR\tXCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL)\r\n/*  This one should only get defined if the corresponding intlevel paddr macro exists:  */\r\n# define XCHAL_DEBUG_VECTOR_PADDR\tXCHAL_INTLEVEL_VECTOR_PADDR(XCHAL_DEBUGLEVEL)\r\n#endif\r\n#endif\r\n\r\n/*  Indexing macros:  */\r\n#define _XCHAL_INTLEVEL_VECTOR_VADDR(n)\t\tXCHAL_INTLEVEL ## n ## _VECTOR_VADDR\r\n#define XCHAL_INTLEVEL_VECTOR_VADDR(n)\t\t_XCHAL_INTLEVEL_VECTOR_VADDR(n)\t\t/* n = 0 .. 15 */\r\n\r\n/*\r\n *  General Exception Causes\r\n *  (values of EXCCAUSE special register set by general exceptions,\r\n *   which vector to the user, kernel, or double-exception vectors).\r\n *\r\n *  DEPRECATED.  Please use the equivalent EXCCAUSE_xxx macros\r\n *  defined in <xtensa/corebits.h>.  (Note that these have slightly\r\n *  different names, they don't just have the XCHAL_ prefix removed.)\r\n */\r\n#define XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION\t\t0\t/* Illegal Instruction */\r\n#define XCHAL_EXCCAUSE_SYSTEM_CALL\t\t\t1\t/* System Call */\r\n#define XCHAL_EXCCAUSE_INSTRUCTION_FETCH_ERROR\t\t2\t/* Instruction Fetch Error */\r\n#define XCHAL_EXCCAUSE_LOAD_STORE_ERROR\t\t\t3\t/* Load Store Error */\r\n#define XCHAL_EXCCAUSE_LEVEL1_INTERRUPT\t\t\t4\t/* Level 1 Interrupt */\r\n#define XCHAL_EXCCAUSE_ALLOCA\t\t\t\t5\t/* Stack Extension Assist */\r\n#define XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO\t\t6\t/* Integer Divide by Zero */\r\n#define XCHAL_EXCCAUSE_SPECULATION\t\t\t7\t/* Speculation */\r\n#define XCHAL_EXCCAUSE_PRIVILEGED\t\t\t8\t/* Privileged Instruction */\r\n#define XCHAL_EXCCAUSE_UNALIGNED\t\t\t9\t/* Unaligned Load Store */\r\n/*10..15 reserved*/\r\n#define XCHAL_EXCCAUSE_ITLB_MISS\t\t\t16\t/* ITlb Miss Exception */\r\n#define XCHAL_EXCCAUSE_ITLB_MULTIHIT\t\t\t17\t/* ITlb Mutltihit Exception */\r\n#define XCHAL_EXCCAUSE_ITLB_PRIVILEGE\t\t\t18\t/* ITlb Privilege Exception */\r\n#define XCHAL_EXCCAUSE_ITLB_SIZE_RESTRICTION\t\t19\t/* ITlb Size Restriction Exception */\r\n#define XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE\t\t20\t/* Fetch Cache Attribute Exception */\r\n/*21..23 reserved*/\r\n#define XCHAL_EXCCAUSE_DTLB_MISS\t\t\t24\t/* DTlb Miss Exception */\r\n#define XCHAL_EXCCAUSE_DTLB_MULTIHIT\t\t\t25\t/* DTlb Multihit Exception */\r\n#define XCHAL_EXCCAUSE_DTLB_PRIVILEGE\t\t\t26\t/* DTlb Privilege Exception */\r\n#define XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION\t\t27\t/* DTlb Size Restriction Exception */\r\n#define XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE\t\t28\t/* Load Cache Attribute Exception */\r\n#define XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE\t\t29\t/* Store Cache Attribute Exception */\r\n/*30..31 reserved*/\r\n#define XCHAL_EXCCAUSE_COPROCESSOR0_DISABLED\t\t32\t/* Coprocessor 0 disabled */\r\n#define XCHAL_EXCCAUSE_COPROCESSOR1_DISABLED\t\t33\t/* Coprocessor 1 disabled */\r\n#define XCHAL_EXCCAUSE_COPROCESSOR2_DISABLED\t\t34\t/* Coprocessor 2 disabled */\r\n#define XCHAL_EXCCAUSE_COPROCESSOR3_DISABLED\t\t35\t/* Coprocessor 3 disabled */\r\n#define XCHAL_EXCCAUSE_COPROCESSOR4_DISABLED\t\t36\t/* Coprocessor 4 disabled */\r\n#define XCHAL_EXCCAUSE_COPROCESSOR5_DISABLED\t\t37\t/* Coprocessor 5 disabled */\r\n#define XCHAL_EXCCAUSE_COPROCESSOR6_DISABLED\t\t38\t/* Coprocessor 6 disabled */\r\n#define XCHAL_EXCCAUSE_COPROCESSOR7_DISABLED\t\t39\t/* Coprocessor 7 disabled */\r\n#define XCHAL_EXCCAUSE_FLOATING_POINT\t\t\t40\t/* Floating Point Exception */\r\n/*40..63 reserved*/\r\n\r\n\r\n/*\r\n *  Miscellaneous special register fields.\r\n *\r\n *  For each special register, and each field within each register:\r\n *\tXCHAL_<regname>_VALIDMASK is the set of bits defined in the register.\r\n *\tXCHAL_<regname>_<field>_BITS is the number of bits in the field.\r\n *\tXCHAL_<regname>_<field>_NUM is 2^bits, the number of possible values\r\n *\t\t\tof the field.\r\n *\tXCHAL_<regname>_<field>_SHIFT is the position of the field within\r\n *\t\t\tthe register, starting from the least significant bit.\r\n *\r\n *  DEPRECATED.  Please use the equivalent macros defined in\r\n *  <xtensa/corebits.h>.  (Note that these have different names.)\r\n */\r\n\r\n/*  DBREAKC (special register number 160):  */\r\n#define XCHAL_DBREAKC_VALIDMASK\t\t0xC000003F\r\n#define XCHAL_DBREAKC_MASK_BITS \t6\r\n#define XCHAL_DBREAKC_MASK_NUM  \t64\r\n#define XCHAL_DBREAKC_MASK_SHIFT\t0\r\n#define XCHAL_DBREAKC_MASK_MASK \t0x0000003F\r\n#define XCHAL_DBREAKC_LOADBREAK_BITS \t1\r\n#define XCHAL_DBREAKC_LOADBREAK_NUM  \t2\r\n#define XCHAL_DBREAKC_LOADBREAK_SHIFT\t30\r\n#define XCHAL_DBREAKC_LOADBREAK_MASK \t0x40000000\r\n#define XCHAL_DBREAKC_STOREBREAK_BITS \t1\r\n#define XCHAL_DBREAKC_STOREBREAK_NUM  \t2\r\n#define XCHAL_DBREAKC_STOREBREAK_SHIFT\t31\r\n#define XCHAL_DBREAKC_STOREBREAK_MASK \t0x80000000\r\n/*  PS (special register number 230):  */\r\n#define XCHAL_PS_VALIDMASK\t\t0x00070F3F\r\n#define XCHAL_PS_INTLEVEL_BITS \t\t4\r\n#define XCHAL_PS_INTLEVEL_NUM  \t\t16\r\n#define XCHAL_PS_INTLEVEL_SHIFT\t\t0\r\n#define XCHAL_PS_INTLEVEL_MASK \t\t0x0000000F\r\n#define XCHAL_PS_EXCM_BITS \t\t1\r\n#define XCHAL_PS_EXCM_NUM  \t\t2\r\n#define XCHAL_PS_EXCM_SHIFT\t\t4\r\n#define XCHAL_PS_EXCM_MASK \t\t0x00000010\r\n#define XCHAL_PS_UM_BITS \t\t1\r\n#define XCHAL_PS_UM_NUM  \t\t2\r\n#define XCHAL_PS_UM_SHIFT\t\t5\r\n#define XCHAL_PS_UM_MASK \t\t0x00000020\r\n#define XCHAL_PS_RING_BITS \t\t2\r\n#define XCHAL_PS_RING_NUM  \t\t4\r\n#define XCHAL_PS_RING_SHIFT\t\t6\r\n#define XCHAL_PS_RING_MASK \t\t0x000000C0\r\n#define XCHAL_PS_OWB_BITS \t\t4\r\n#define XCHAL_PS_OWB_NUM  \t\t16\r\n#define XCHAL_PS_OWB_SHIFT\t\t8\r\n#define XCHAL_PS_OWB_MASK \t\t0x00000F00\r\n#define XCHAL_PS_CALLINC_BITS \t\t2\r\n#define XCHAL_PS_CALLINC_NUM  \t\t4\r\n#define XCHAL_PS_CALLINC_SHIFT\t\t16\r\n#define XCHAL_PS_CALLINC_MASK \t\t0x00030000\r\n#define XCHAL_PS_WOE_BITS \t\t1\r\n#define XCHAL_PS_WOE_NUM  \t\t2\r\n#define XCHAL_PS_WOE_SHIFT\t\t18\r\n#define XCHAL_PS_WOE_MASK \t\t0x00040000\r\n/*  EXCCAUSE (special register number 232):  */\r\n#define XCHAL_EXCCAUSE_VALIDMASK\t0x0000003F\r\n#define XCHAL_EXCCAUSE_BITS \t\t6\r\n#define XCHAL_EXCCAUSE_NUM  \t\t64\r\n#define XCHAL_EXCCAUSE_SHIFT\t\t0\r\n#define XCHAL_EXCCAUSE_MASK \t\t0x0000003F\r\n/*  DEBUGCAUSE (special register number 233):  */\r\n#define XCHAL_DEBUGCAUSE_VALIDMASK\t0x0000003F\r\n#define XCHAL_DEBUGCAUSE_ICOUNT_BITS \t1\r\n#define XCHAL_DEBUGCAUSE_ICOUNT_NUM  \t2\r\n#define XCHAL_DEBUGCAUSE_ICOUNT_SHIFT\t0\r\n#define XCHAL_DEBUGCAUSE_ICOUNT_MASK \t0x00000001\r\n#define XCHAL_DEBUGCAUSE_IBREAK_BITS \t1\r\n#define XCHAL_DEBUGCAUSE_IBREAK_NUM  \t2\r\n#define XCHAL_DEBUGCAUSE_IBREAK_SHIFT\t1\r\n#define XCHAL_DEBUGCAUSE_IBREAK_MASK \t0x00000002\r\n#define XCHAL_DEBUGCAUSE_DBREAK_BITS \t1\r\n#define XCHAL_DEBUGCAUSE_DBREAK_NUM  \t2\r\n#define XCHAL_DEBUGCAUSE_DBREAK_SHIFT\t2\r\n#define XCHAL_DEBUGCAUSE_DBREAK_MASK \t0x00000004\r\n#define XCHAL_DEBUGCAUSE_BREAK_BITS \t1\r\n#define XCHAL_DEBUGCAUSE_BREAK_NUM  \t2\r\n#define XCHAL_DEBUGCAUSE_BREAK_SHIFT\t3\r\n#define XCHAL_DEBUGCAUSE_BREAK_MASK \t0x00000008\r\n#define XCHAL_DEBUGCAUSE_BREAKN_BITS \t1\r\n#define XCHAL_DEBUGCAUSE_BREAKN_NUM  \t2\r\n#define XCHAL_DEBUGCAUSE_BREAKN_SHIFT\t4\r\n#define XCHAL_DEBUGCAUSE_BREAKN_MASK \t0x00000010\r\n#define XCHAL_DEBUGCAUSE_DEBUGINT_BITS \t1\r\n#define XCHAL_DEBUGCAUSE_DEBUGINT_NUM  \t2\r\n#define XCHAL_DEBUGCAUSE_DEBUGINT_SHIFT\t5\r\n#define XCHAL_DEBUGCAUSE_DEBUGINT_MASK \t0x00000020\r\n\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tTIMERS\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*#define XCHAL_HAVE_TIMERS\t\tXCHAL_HAVE_CCOUNT*/\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tINTERNAL I/D RAM/ROMs and XLMI\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define  XCHAL_NUM_IROM\t\tXCHAL_NUM_INSTROM\t/* (DEPRECATED) */\r\n#define  XCHAL_NUM_IRAM\t\tXCHAL_NUM_INSTRAM\t/* (DEPRECATED) */\r\n#define  XCHAL_NUM_DROM\t\tXCHAL_NUM_DATAROM\t/* (DEPRECATED) */\r\n#define  XCHAL_NUM_DRAM\t\tXCHAL_NUM_DATARAM\t/* (DEPRECATED) */\r\n\r\n#define XCHAL_IROM0_VADDR\tXCHAL_INSTROM0_VADDR\t/* (DEPRECATED) */\r\n#define XCHAL_IROM0_PADDR\tXCHAL_INSTROM0_PADDR\t/* (DEPRECATED) */\r\n#define XCHAL_IROM0_SIZE\tXCHAL_INSTROM0_SIZE\t/* (DEPRECATED) */\r\n#define XCHAL_IROM1_VADDR\tXCHAL_INSTROM1_VADDR\t/* (DEPRECATED) */\r\n#define XCHAL_IROM1_PADDR\tXCHAL_INSTROM1_PADDR\t/* (DEPRECATED) */\r\n#define XCHAL_IROM1_SIZE\tXCHAL_INSTROM1_SIZE\t/* (DEPRECATED) */\r\n#define XCHAL_IRAM0_VADDR\tXCHAL_INSTRAM0_VADDR\t/* (DEPRECATED) */\r\n#define XCHAL_IRAM0_PADDR\tXCHAL_INSTRAM0_PADDR\t/* (DEPRECATED) */\r\n#define XCHAL_IRAM0_SIZE\tXCHAL_INSTRAM0_SIZE\t/* (DEPRECATED) */\r\n#define XCHAL_IRAM1_VADDR\tXCHAL_INSTRAM1_VADDR\t/* (DEPRECATED) */\r\n#define XCHAL_IRAM1_PADDR\tXCHAL_INSTRAM1_PADDR\t/* (DEPRECATED) */\r\n#define XCHAL_IRAM1_SIZE\tXCHAL_INSTRAM1_SIZE\t/* (DEPRECATED) */\r\n#define XCHAL_DROM0_VADDR\tXCHAL_DATAROM0_VADDR\t/* (DEPRECATED) */\r\n#define XCHAL_DROM0_PADDR\tXCHAL_DATAROM0_PADDR\t/* (DEPRECATED) */\r\n#define XCHAL_DROM0_SIZE\tXCHAL_DATAROM0_SIZE\t/* (DEPRECATED) */\r\n#define XCHAL_DROM1_VADDR\tXCHAL_DATAROM1_VADDR\t/* (DEPRECATED) */\r\n#define XCHAL_DROM1_PADDR\tXCHAL_DATAROM1_PADDR\t/* (DEPRECATED) */\r\n#define XCHAL_DROM1_SIZE\tXCHAL_DATAROM1_SIZE\t/* (DEPRECATED) */\r\n#define XCHAL_DRAM0_VADDR\tXCHAL_DATARAM0_VADDR\t/* (DEPRECATED) */\r\n#define XCHAL_DRAM0_PADDR\tXCHAL_DATARAM0_PADDR\t/* (DEPRECATED) */\r\n#define XCHAL_DRAM0_SIZE\tXCHAL_DATARAM0_SIZE\t/* (DEPRECATED) */\r\n#define XCHAL_DRAM1_VADDR\tXCHAL_DATARAM1_VADDR\t/* (DEPRECATED) */\r\n#define XCHAL_DRAM1_PADDR\tXCHAL_DATARAM1_PADDR\t/* (DEPRECATED) */\r\n#define XCHAL_DRAM1_SIZE\tXCHAL_DATARAM1_SIZE\t/* (DEPRECATED) */\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tCACHE\r\n  ----------------------------------------------------------------------*/\r\n\r\n\r\n/*  Default PREFCTL value to enable prefetch.  */\r\n#define XCHAL_CACHE_PREFCTL_DEFAULT\t0x44\r\n\r\n\r\n/*  Max for both I-cache and D-cache (used for general alignment):  */\r\n#if XCHAL_ICACHE_LINESIZE > XCHAL_DCACHE_LINESIZE\r\n# define XCHAL_CACHE_LINEWIDTH_MAX\tXCHAL_ICACHE_LINEWIDTH\r\n# define XCHAL_CACHE_LINESIZE_MAX\tXCHAL_ICACHE_LINESIZE\r\n#else\r\n# define XCHAL_CACHE_LINEWIDTH_MAX\tXCHAL_DCACHE_LINEWIDTH\r\n# define XCHAL_CACHE_LINESIZE_MAX\tXCHAL_DCACHE_LINESIZE\r\n#endif\r\n\r\n#define XCHAL_ICACHE_SETSIZE\t\t(1<<XCHAL_ICACHE_SETWIDTH)\r\n#define XCHAL_DCACHE_SETSIZE\t\t(1<<XCHAL_DCACHE_SETWIDTH)\r\n/*  Max for both I and D caches (used for cache-coherency page alignment):  */\r\n#if XCHAL_ICACHE_SETWIDTH > XCHAL_DCACHE_SETWIDTH\r\n# define XCHAL_CACHE_SETWIDTH_MAX\tXCHAL_ICACHE_SETWIDTH\r\n# define XCHAL_CACHE_SETSIZE_MAX\tXCHAL_ICACHE_SETSIZE\r\n#else\r\n# define XCHAL_CACHE_SETWIDTH_MAX\tXCHAL_DCACHE_SETWIDTH\r\n# define XCHAL_CACHE_SETSIZE_MAX\tXCHAL_DCACHE_SETSIZE\r\n#endif\r\n\r\n/*  Instruction cache tag bits:  */\r\n#define XCHAL_ICACHE_TAG_V_SHIFT\t0\r\n#define XCHAL_ICACHE_TAG_V\t\t0x1\t/* valid bit */\r\n#if XCHAL_ICACHE_WAYS > 1\r\n# define XCHAL_ICACHE_TAG_F_SHIFT\t1\r\n# define XCHAL_ICACHE_TAG_F\t\t0x2\t/* fill (LRU) bit */\r\n#else\r\n# define XCHAL_ICACHE_TAG_F_SHIFT\t0\r\n# define XCHAL_ICACHE_TAG_F\t\t0\t/* no fill (LRU) bit */\r\n#endif\r\n#if XCHAL_ICACHE_LINE_LOCKABLE\r\n# define XCHAL_ICACHE_TAG_L_SHIFT\t(XCHAL_ICACHE_TAG_F_SHIFT+1)\r\n# define XCHAL_ICACHE_TAG_L\t\t(1 << XCHAL_ICACHE_TAG_L_SHIFT)\t/* lock bit */\r\n#else\r\n# define XCHAL_ICACHE_TAG_L_SHIFT\tXCHAL_ICACHE_TAG_F_SHIFT\r\n# define XCHAL_ICACHE_TAG_L\t\t0\t/* no lock bit */\r\n#endif\r\n/*  Data cache tag bits:  */\r\n#define XCHAL_DCACHE_TAG_V_SHIFT\t0\r\n#define XCHAL_DCACHE_TAG_V\t\t0x1\t/* valid bit */\r\n#if XCHAL_DCACHE_WAYS > 1\r\n# define XCHAL_DCACHE_TAG_F_SHIFT\t1\r\n# define XCHAL_DCACHE_TAG_F\t\t0x2\t/* fill (LRU) bit */\r\n#else\r\n# define XCHAL_DCACHE_TAG_F_SHIFT\t0\r\n# define XCHAL_DCACHE_TAG_F\t\t0\t/* no fill (LRU) bit */\r\n#endif\r\n#if XCHAL_DCACHE_IS_WRITEBACK\r\n# define XCHAL_DCACHE_TAG_D_SHIFT\t(XCHAL_DCACHE_TAG_F_SHIFT+1)\r\n# define XCHAL_DCACHE_TAG_D\t\t(1 << XCHAL_DCACHE_TAG_D_SHIFT)\t/* dirty bit */\r\n#else\r\n# define XCHAL_DCACHE_TAG_D_SHIFT\tXCHAL_DCACHE_TAG_F_SHIFT\r\n# define XCHAL_DCACHE_TAG_D\t\t0\t/* no dirty bit */\r\n#endif\r\n#if XCHAL_DCACHE_LINE_LOCKABLE\r\n# define XCHAL_DCACHE_TAG_L_SHIFT\t(XCHAL_DCACHE_TAG_D_SHIFT+1)\r\n# define XCHAL_DCACHE_TAG_L\t\t(1 << XCHAL_DCACHE_TAG_D_SHIFT)\t/* lock bit */\r\n#else\r\n# define XCHAL_DCACHE_TAG_L_SHIFT\tXCHAL_DCACHE_TAG_D_SHIFT\r\n# define XCHAL_DCACHE_TAG_L\t\t0\t/* no lock bit */\r\n#endif\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tMMU\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  See <xtensa/config/core-matmap.h> for more details.  */\r\n\r\n/*  Has different semantic in open source headers (where it means HAVE_PTP_MMU),\r\n    so comment out starting with RB-2008.3 release; later, might get\r\n    get reintroduced as a synonym for XCHAL_HAVE_PTP_MMU instead:  */\r\n/*#define XCHAL_HAVE_MMU\t\tXCHAL_HAVE_TLBS*/\t/* (DEPRECATED; use XCHAL_HAVE_TLBS instead) */\r\n\r\n/*  Indexing macros:  */\r\n#define _XCHAL_ITLB_SET(n,_what)\tXCHAL_ITLB_SET ## n ## _what\r\n#define XCHAL_ITLB_SET(n,what)\t\t_XCHAL_ITLB_SET(n, _ ## what )\r\n#define _XCHAL_ITLB_SET_E(n,i,_what)\tXCHAL_ITLB_SET ## n ## _E ## i ## _what\r\n#define XCHAL_ITLB_SET_E(n,i,what)\t_XCHAL_ITLB_SET_E(n,i, _ ## what )\r\n#define _XCHAL_DTLB_SET(n,_what)\tXCHAL_DTLB_SET ## n ## _what\r\n#define XCHAL_DTLB_SET(n,what)\t\t_XCHAL_DTLB_SET(n, _ ## what )\r\n#define _XCHAL_DTLB_SET_E(n,i,_what)\tXCHAL_DTLB_SET ## n ## _E ## i ## _what\r\n#define XCHAL_DTLB_SET_E(n,i,what)\t_XCHAL_DTLB_SET_E(n,i, _ ## what )\r\n/*\r\n *  Example use:  XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES)\r\n *\tto get the value of XCHAL_ITLB_SET<n>_ENTRIES where <n> is the first auto-refill set.\r\n */\r\n\r\n/*  Number of entries per autorefill way:  */\r\n#define XCHAL_ITLB_ARF_ENTRIES\t\t(1<<XCHAL_ITLB_ARF_ENTRIES_LOG2)\r\n#define XCHAL_DTLB_ARF_ENTRIES\t\t(1<<XCHAL_DTLB_ARF_ENTRIES_LOG2)\r\n\r\n/*\r\n *  Determine whether we have a full MMU (with Page Table and Protection)\r\n *  usable for an MMU-based OS:\r\n */\r\n#if 0\r\n#if XCHAL_HAVE_TLBS && !XCHAL_HAVE_SPANNING_WAY && XCHAL_ITLB_ARF_WAYS > 0 && XCHAL_DTLB_ARF_WAYS > 0 && XCHAL_MMU_RINGS >= 2\r\n# define XCHAL_HAVE_PTP_MMU\t\t1\t/* have full MMU (with page table [autorefill] and protection) */\r\n#else\r\n# define XCHAL_HAVE_PTP_MMU\t\t0\t/* don't have full MMU */\r\n#endif\r\n#endif\r\n\r\n/*\r\n *  For full MMUs, report kernel RAM segment and kernel I/O segment static page mappings:\r\n */\r\n#if XCHAL_HAVE_PTP_MMU && !XCHAL_HAVE_SPANNING_WAY\r\n#define XCHAL_KSEG_CACHED_VADDR\t\t0xD0000000\t/* virt.addr of kernel RAM cached static map */\r\n#define XCHAL_KSEG_CACHED_PADDR\t\t0x00000000\t/* phys.addr of kseg_cached */\r\n#define XCHAL_KSEG_CACHED_SIZE\t\t0x08000000\t/* size in bytes of kseg_cached (assumed power of 2!!!) */\r\n#define XCHAL_KSEG_BYPASS_VADDR\t\t0xD8000000\t/* virt.addr of kernel RAM bypass (uncached) static map */\r\n#define XCHAL_KSEG_BYPASS_PADDR\t\t0x00000000\t/* phys.addr of kseg_bypass */\r\n#define XCHAL_KSEG_BYPASS_SIZE\t\t0x08000000\t/* size in bytes of kseg_bypass (assumed power of 2!!!) */\r\n\r\n#define XCHAL_KIO_CACHED_VADDR\t\t0xE0000000\t/* virt.addr of kernel I/O cached static map */\r\n#define XCHAL_KIO_CACHED_PADDR\t\t0xF0000000\t/* phys.addr of kio_cached */\r\n#define XCHAL_KIO_CACHED_SIZE\t\t0x10000000\t/* size in bytes of kio_cached (assumed power of 2!!!) */\r\n#define XCHAL_KIO_BYPASS_VADDR\t\t0xF0000000\t/* virt.addr of kernel I/O bypass (uncached) static map */\r\n#define XCHAL_KIO_BYPASS_PADDR\t\t0xF0000000\t/* phys.addr of kio_bypass */\r\n#define XCHAL_KIO_BYPASS_SIZE\t\t0x10000000\t/* size in bytes of kio_bypass (assumed power of 2!!!) */\r\n\r\n#define XCHAL_SEG_MAPPABLE_VADDR\t0x00000000\t/* start of largest non-static-mapped virtual addr area */\r\n#define XCHAL_SEG_MAPPABLE_SIZE\t\t0xD0000000\t/* size in bytes of  \"  */\r\n/* define XCHAL_SEG_MAPPABLE2_xxx if more areas present, sorted in order of descending size.  */\r\n#endif\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tMISC\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  Data alignment required if used for instructions:  */\r\n#if XCHAL_INST_FETCH_WIDTH > XCHAL_DATA_WIDTH\r\n# define XCHAL_ALIGN_MAX\t\tXCHAL_INST_FETCH_WIDTH\r\n#else\r\n# define XCHAL_ALIGN_MAX\t\tXCHAL_DATA_WIDTH\r\n#endif\r\n\r\n/*\r\n *  Names kept for backward compatibility.\r\n *  (Here \"RELEASE\" is now a misnomer; these are product *versions*, not the releases\r\n *   under which they are released.  In the T10##.# era there was no distinction.)\r\n */\r\n#define XCHAL_HW_RELEASE_MAJOR\t\tXCHAL_HW_VERSION_MAJOR\r\n#define XCHAL_HW_RELEASE_MINOR\t\tXCHAL_HW_VERSION_MINOR\r\n#define XCHAL_HW_RELEASE_NAME\t\tXCHAL_HW_VERSION_NAME\r\n\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tCOPROCESSORS and EXTRA STATE\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XCHAL_EXTRA_SA_SIZE\t\tXCHAL_NCP_SA_SIZE\r\n#define XCHAL_EXTRA_SA_ALIGN\t\tXCHAL_NCP_SA_ALIGN\r\n#define XCHAL_CPEXTRA_SA_SIZE\t\tXCHAL_TOTAL_SA_SIZE\r\n#define XCHAL_CPEXTRA_SA_ALIGN\t\tXCHAL_TOTAL_SA_ALIGN\r\n\r\n#if defined (_ASMLANGUAGE) || defined (__ASSEMBLER__)\r\n\r\n\t/*  Invoked at start of save area load/store sequence macro to setup macro\r\n\t *  internal offsets.  Not usually invoked directly.\r\n\t *\tcontinue\t0 for 1st sequence, 1 for subsequent consecutive ones.\r\n\t *\ttotofs\t\toffset from original ptr to next load/store location.\r\n\t */\r\n\t.macro\txchal_sa_start\tcontinue totofs\r\n\t.ifeq \\continue\r\n\t .set\t.Lxchal_pofs_, 0\t/* offset from original ptr to current \\ptr */\r\n\t .set\t.Lxchal_ofs_, 0\t\t/* offset from current \\ptr to next load/store location */\r\n\t.endif\r\n\t.if \\totofs + 1\t\t\t/* if totofs specified (not -1) */\r\n\t .set\t.Lxchal_ofs_, \\totofs - .Lxchal_pofs_\t/* specific offset from original ptr */\r\n\t.endif\r\n\t.endm\r\n\r\n\t/*  Align portion of save area and bring ptr in range if necessary.\r\n\t *  Used by save area load/store sequences.  Not usually invoked directly.\r\n\t *  Allows combining multiple (sub-)sequences arbitrarily.\r\n\t *\tptr\t\tpointer to save area (may be off, see .Lxchal_pofs_)\r\n\t *\tminofs,maxofs\trange of offset from cur ptr to next load/store loc;\r\n\t *\t\t\tminofs <= 0 <= maxofs  (0 must always be valid offset)\r\n\t *\t\t\trange must be within +/- 30kB or so.\r\n\t *\tofsalign\talignment granularity of minofs .. maxofs (pow of 2)\r\n\t *\t\t\t(restriction on offset from ptr to next load/store loc)\r\n\t *\ttotalign\talign from orig ptr to next load/store loc (pow of 2)\r\n\t */\r\n\t.macro\txchal_sa_align\tptr minofs maxofs ofsalign totalign\r\n\t.set\t.Lxchal_ofs_, ((.Lxchal_pofs_ + .Lxchal_ofs_ + \\totalign - 1) & -\\totalign) - .Lxchal_pofs_\r\n\t/*  If necessary, adjust \\ptr to bring .Lxchal_ofs_ in acceptable range:  */\r\n\t.if (((\\maxofs) - .Lxchal_ofs_) & 0xC0000000) | ((.Lxchal_ofs_ - (\\minofs)) & 0xC0000000) | (.Lxchal_ofs_ & (\\ofsalign-1))\r\n\t .set\t.Ligmask, 0xFFFFFFFF\t/* TODO: optimize to addmi, per aligns and .Lxchal_ofs_ */\r\n\t addi\t\\ptr, \\ptr, (.Lxchal_ofs_ & .Ligmask)\r\n\t .set\t.Lxchal_pofs_, .Lxchal_pofs_ + (.Lxchal_ofs_ & .Ligmask)\r\n\t .set\t.Lxchal_ofs_, (.Lxchal_ofs_ & ~.Ligmask)\r\n\t.endif\r\n\t.endm\r\n\t/*\r\n\t *  We could optimize for addi to expand to only addmi instead of\r\n\t *  \"addmi;addi\", where possible.  Here's a partial example how:\r\n\t * .set\t.Lmaxmask, -(\\ofsalign) & -(\\totalign)\r\n\t * .if (((\\maxofs) + ~.Lmaxmask + 1) & 0xFFFFFF00) && ((.Lxchal_ofs_ & ~.Lmaxmask) == 0)\r\n\t *  .set\t.Ligmask, 0xFFFFFF00\r\n\t * .elif ... ditto for negative ofs range ...\r\n\t *  .set .Ligmask, 0xFFFFFF00\r\n\t *  .set ... adjust per offset ...\r\n\t * .else\r\n\t *  .set .Ligmask, 0xFFFFFFFF\r\n\t * .endif\r\n\t */\r\n\r\n\t/*  Invoke this after xchal_XXX_{load,store} macros to restore \\ptr.  */\r\n\t.macro\txchal_sa_ptr_restore\tptr\r\n\t.if .Lxchal_pofs_\r\n\t addi\t\\ptr, \\ptr, - .Lxchal_pofs_\r\n\t .set\t.Lxchal_ofs_, .Lxchal_ofs_ + .Lxchal_pofs_\r\n\t .set\t.Lxchal_pofs_, 0\r\n\t.endif\r\n\t.endm\r\n\r\n\t/*\r\n\t *  Use as eg:\r\n\t *\txchal_atmps_store a1, SOMEOFS, XCHAL_SA_NUM_ATMPS, a4, a5\r\n\t *\txchal_ncp_load a2, a0,a3,a4,a5\r\n\t *\txchal_atmps_load  a1, SOMEOFS, XCHAL_SA_NUM_ATMPS, a4, a5\r\n\t *\r\n\t *  Specify only the ARs you *haven't* saved/restored already, up to 4.\r\n\t *  They *must* be the *last* ARs (in same order) specified to save area\r\n\t *  load/store sequences.  In the example above, a0 and a3 were already\r\n\t *  saved/restored and unused (thus available) but a4 and a5 were not.\r\n\t */\r\n#define xchal_atmps_store\txchal_atmps_loadstore s32i,\r\n#define xchal_atmps_load\txchal_atmps_loadstore l32i,\r\n\t.macro\txchal_atmps_loadstore\tinst ptr offset nreq aa=0 ab=0 ac=0 ad=0\r\n\t.set\t.Lnsaved_, 0\r\n\t.irp\treg,\\aa,\\ab,\\ac,\\ad\r\n\t .ifeq 0x\\reg ; .set .Lnsaved_,.Lnsaved_+1 ; .endif\r\n\t.endr\r\n\t.set\t.Laofs_, 0\r\n\t.irp\treg,\\aa,\\ab,\\ac,\\ad\r\n\t .ifgt (\\nreq)-.Lnsaved_\r\n\t  \\inst\t\\reg, \\ptr, .Laofs_+\\offset\r\n\t  .set\t.Laofs_,.Laofs_+4\r\n\t  .set\t.Lnsaved_,.Lnsaved_+1\r\n\t .endif\r\n\t.endr\r\n\t.endm\r\n\r\n/*#define xchal_ncp_load_a2\txchal_ncp_load\ta2,a3,a4,a5,a6*/\r\n/*#define xchal_ncp_store_a2\txchal_ncp_store\ta2,a3,a4,a5,a6*/\r\n#define xchal_extratie_load\t\txchal_ncptie_load\r\n#define xchal_extratie_store\t\txchal_ncptie_store\r\n#define xchal_extratie_load_a2\t\txchal_ncptie_load  a2,a3,a4,a5,a6\r\n#define xchal_extratie_store_a2\t\txchal_ncptie_store a2,a3,a4,a5,a6\r\n#define xchal_extra_load\t\txchal_ncp_load\r\n#define xchal_extra_store\t\txchal_ncp_store\r\n#define xchal_extra_load_a2\t\txchal_ncp_load  a2,a3,a4,a5,a6\r\n#define xchal_extra_store_a2\t\txchal_ncp_store a2,a3,a4,a5,a6\r\n#define xchal_extra_load_funcbody\txchal_ncp_load  a2,a3,a4,a5,a6\r\n#define xchal_extra_store_funcbody\txchal_ncp_store a2,a3,a4,a5,a6\r\n#define xchal_cp0_store_a2\t\txchal_cp0_store  a2,a3,a4,a5,a6\r\n#define xchal_cp0_load_a2\t\txchal_cp0_load   a2,a3,a4,a5,a6\r\n#define xchal_cp1_store_a2\t\txchal_cp1_store  a2,a3,a4,a5,a6\r\n#define xchal_cp1_load_a2\t\txchal_cp1_load   a2,a3,a4,a5,a6\r\n#define xchal_cp2_store_a2\t\txchal_cp2_store  a2,a3,a4,a5,a6\r\n#define xchal_cp2_load_a2\t\txchal_cp2_load   a2,a3,a4,a5,a6\r\n#define xchal_cp3_store_a2\t\txchal_cp3_store  a2,a3,a4,a5,a6\r\n#define xchal_cp3_load_a2\t\txchal_cp3_load   a2,a3,a4,a5,a6\r\n#define xchal_cp4_store_a2\t\txchal_cp4_store  a2,a3,a4,a5,a6\r\n#define xchal_cp4_load_a2\t\txchal_cp4_load   a2,a3,a4,a5,a6\r\n#define xchal_cp5_store_a2\t\txchal_cp5_store  a2,a3,a4,a5,a6\r\n#define xchal_cp5_load_a2\t\txchal_cp5_load   a2,a3,a4,a5,a6\r\n#define xchal_cp6_store_a2\t\txchal_cp6_store  a2,a3,a4,a5,a6\r\n#define xchal_cp6_load_a2\t\txchal_cp6_load   a2,a3,a4,a5,a6\r\n#define xchal_cp7_store_a2\t\txchal_cp7_store  a2,a3,a4,a5,a6\r\n#define xchal_cp7_load_a2\t\txchal_cp7_load   a2,a3,a4,a5,a6\r\n\r\n/*  Empty placeholder macros for undefined coprocessors:  */\r\n#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK) == 0\r\n# if XCHAL_CP0_SA_SIZE == 0\r\n\t.macro xchal_cp0_store\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n\t.macro xchal_cp0_load\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n# endif\r\n# if XCHAL_CP1_SA_SIZE == 0\r\n\t.macro xchal_cp1_store\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n\t.macro xchal_cp1_load\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n# endif\r\n# if XCHAL_CP2_SA_SIZE == 0\r\n\t.macro xchal_cp2_store\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n\t.macro xchal_cp2_load\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n# endif\r\n# if XCHAL_CP3_SA_SIZE == 0\r\n\t.macro xchal_cp3_store\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n\t.macro xchal_cp3_load\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n# endif\r\n# if XCHAL_CP4_SA_SIZE == 0\r\n\t.macro xchal_cp4_store\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n\t.macro xchal_cp4_load\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n# endif\r\n# if XCHAL_CP5_SA_SIZE == 0\r\n\t.macro xchal_cp5_store\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n\t.macro xchal_cp5_load\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n# endif\r\n# if XCHAL_CP6_SA_SIZE == 0\r\n\t.macro xchal_cp6_store\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n\t.macro xchal_cp6_load\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n# endif\r\n# if XCHAL_CP7_SA_SIZE == 0\r\n\t.macro xchal_cp7_store\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n\t.macro xchal_cp7_load\tp a b c d continue=0 ofs=-1 select=-1 ; .endm\r\n# endif\r\n#endif\r\n\r\n\t/********************\r\n\t *  Macros to create functions that save and restore the state of *any* TIE\r\n\t *  coprocessor (by dynamic index).\r\n\t */\r\n\r\n\t/*\r\n\t *  Macro that expands to the body of a function\r\n\t *  that stores the selected coprocessor's state (registers etc).\r\n\t *\tEntry:\ta2 = ptr to save area in which to save cp state\r\n\t *\t\ta3 = coprocessor number\r\n\t *\tExit:\tany register a2-a15 (?) may have been clobbered.\r\n\t */\r\n\t.macro\txchal_cpi_store_funcbody\r\n#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK)\r\n# if XCHAL_CP0_SA_SIZE\r\n\tbnez\ta3, 99f\r\n\txchal_cp0_store_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP1_SA_SIZE\r\n\tbnei\ta3, 1, 99f\r\n\txchal_cp1_store_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP2_SA_SIZE\r\n\tbnei\ta3, 2, 99f\r\n\txchal_cp2_store_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP3_SA_SIZE\r\n\tbnei\ta3, 3, 99f\r\n\txchal_cp3_store_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP4_SA_SIZE\r\n\tbnei\ta3, 4, 99f\r\n\txchal_cp4_store_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP5_SA_SIZE\r\n\tbnei\ta3, 5, 99f\r\n\txchal_cp5_store_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP6_SA_SIZE\r\n\tbnei\ta3, 6, 99f\r\n\txchal_cp6_store_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP7_SA_SIZE\r\n\tbnei\ta3, 7, 99f\r\n\txchal_cp7_store_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n90:\r\n#endif\r\n\t.endm\r\n\r\n\t/*\r\n\t *  Macro that expands to the body of a function\r\n\t *  that loads the selected coprocessor's state (registers etc).\r\n\t *\tEntry:\ta2 = ptr to save area from which to restore cp state\r\n\t *\t\ta3 = coprocessor number\r\n\t *\tExit:\tany register a2-a15 (?) may have been clobbered.\r\n\t */\r\n\t.macro\txchal_cpi_load_funcbody\r\n#if (XCHAL_CP_MASK & ~XCHAL_CP_PORT_MASK)\r\n# if XCHAL_CP0_SA_SIZE\r\n\tbnez\ta3, 99f\r\n\txchal_cp0_load_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP1_SA_SIZE\r\n\tbnei\ta3, 1, 99f\r\n\txchal_cp1_load_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP2_SA_SIZE\r\n\tbnei\ta3, 2, 99f\r\n\txchal_cp2_load_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP3_SA_SIZE\r\n\tbnei\ta3, 3, 99f\r\n\txchal_cp3_load_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP4_SA_SIZE\r\n\tbnei\ta3, 4, 99f\r\n\txchal_cp4_load_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP5_SA_SIZE\r\n\tbnei\ta3, 5, 99f\r\n\txchal_cp5_load_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP6_SA_SIZE\r\n\tbnei\ta3, 6, 99f\r\n\txchal_cp6_load_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n# if XCHAL_CP7_SA_SIZE\r\n\tbnei\ta3, 7, 99f\r\n\txchal_cp7_load_a2\r\n\tj\t90f\r\n99:\r\n# endif\r\n90:\r\n#endif\r\n\t.endm\r\n\r\n#endif /*_ASMLANGUAGE or __ASSEMBLER__*/\r\n\r\n\r\n/*  Other default macros for undefined coprocessors:  */\r\n#ifndef XCHAL_CP0_NAME\r\n# define XCHAL_CP0_NAME\t\t\t\t0\r\n# define XCHAL_CP0_SA_CONTENTS_LIBDB_NUM\t0\r\n# define XCHAL_CP0_SA_CONTENTS_LIBDB\t\t/* empty */\r\n#endif\r\n#ifndef XCHAL_CP1_NAME\r\n# define XCHAL_CP1_NAME\t\t\t\t0\r\n# define XCHAL_CP1_SA_CONTENTS_LIBDB_NUM\t0\r\n# define XCHAL_CP1_SA_CONTENTS_LIBDB\t\t/* empty */\r\n#endif\r\n#ifndef XCHAL_CP2_NAME\r\n# define XCHAL_CP2_NAME\t\t\t\t0\r\n# define XCHAL_CP2_SA_CONTENTS_LIBDB_NUM\t0\r\n# define XCHAL_CP2_SA_CONTENTS_LIBDB\t\t/* empty */\r\n#endif\r\n#ifndef XCHAL_CP3_NAME\r\n# define XCHAL_CP3_NAME\t\t\t\t0\r\n# define XCHAL_CP3_SA_CONTENTS_LIBDB_NUM\t0\r\n# define XCHAL_CP3_SA_CONTENTS_LIBDB\t\t/* empty */\r\n#endif\r\n#ifndef XCHAL_CP4_NAME\r\n# define XCHAL_CP4_NAME\t\t\t\t0\r\n# define XCHAL_CP4_SA_CONTENTS_LIBDB_NUM\t0\r\n# define XCHAL_CP4_SA_CONTENTS_LIBDB\t\t/* empty */\r\n#endif\r\n#ifndef XCHAL_CP5_NAME\r\n# define XCHAL_CP5_NAME\t\t\t\t0\r\n# define XCHAL_CP5_SA_CONTENTS_LIBDB_NUM\t0\r\n# define XCHAL_CP5_SA_CONTENTS_LIBDB\t\t/* empty */\r\n#endif\r\n#ifndef XCHAL_CP6_NAME\r\n# define XCHAL_CP6_NAME\t\t\t\t0\r\n# define XCHAL_CP6_SA_CONTENTS_LIBDB_NUM\t0\r\n# define XCHAL_CP6_SA_CONTENTS_LIBDB\t\t/* empty */\r\n#endif\r\n#ifndef XCHAL_CP7_NAME\r\n# define XCHAL_CP7_NAME\t\t\t\t0\r\n# define XCHAL_CP7_SA_CONTENTS_LIBDB_NUM\t0\r\n# define XCHAL_CP7_SA_CONTENTS_LIBDB\t\t/* empty */\r\n#endif\r\n\r\n#if XCHAL_CP_MASK == 0\r\n/*  Filler info for unassigned coprocessors, to simplify arrays etc:  */\r\n#define XCHAL_CP0_SA_SIZE               0\r\n#define XCHAL_CP0_SA_ALIGN              1\r\n#define XCHAL_CP1_SA_SIZE               0\r\n#define XCHAL_CP1_SA_ALIGN              1\r\n#define XCHAL_CP2_SA_SIZE               0\r\n#define XCHAL_CP2_SA_ALIGN              1\r\n#define XCHAL_CP3_SA_SIZE               0\r\n#define XCHAL_CP3_SA_ALIGN              1\r\n#define XCHAL_CP4_SA_SIZE               0\r\n#define XCHAL_CP4_SA_ALIGN              1\r\n#define XCHAL_CP5_SA_SIZE               0\r\n#define XCHAL_CP5_SA_ALIGN              1\r\n#define XCHAL_CP6_SA_SIZE               0\r\n#define XCHAL_CP6_SA_ALIGN              1\r\n#define XCHAL_CP7_SA_SIZE               0\r\n#define XCHAL_CP7_SA_ALIGN              1\r\n#endif\r\n\r\n\r\n/*  Indexing macros:  */\r\n#define _XCHAL_CP_SA_SIZE(n)\t\tXCHAL_CP ## n ## _SA_SIZE\r\n#define XCHAL_CP_SA_SIZE(n)\t\t_XCHAL_CP_SA_SIZE(n)\t/* n = 0 .. 7 */\r\n#define _XCHAL_CP_SA_ALIGN(n)\t\tXCHAL_CP ## n ## _SA_ALIGN\r\n#define XCHAL_CP_SA_ALIGN(n)\t\t_XCHAL_CP_SA_ALIGN(n)\t/* n = 0 .. 7 */\r\n\r\n#define XCHAL_CPEXTRA_SA_SIZE_TOR2      XCHAL_CPEXTRA_SA_SIZE\t/* Tor2Beta only - do not use */\r\n\r\n/*  Link-time HAL global variables that report coprocessor numbers by name\r\n    (names are case-preserved from the original TIE):  */\r\n#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__)\r\n# define _XCJOIN(a,b)\ta ## b\r\n# define XCJOIN(a,b)\t_XCJOIN(a,b)\r\n# ifdef XCHAL_CP0_NAME\r\nextern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP0_IDENT);\r\nextern const unsigned int  XCJOIN(Xthal_cp_mask_,XCHAL_CP0_IDENT);\r\n# endif\r\n# ifdef XCHAL_CP1_NAME\r\nextern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP1_IDENT);\r\nextern const unsigned int  XCJOIN(Xthal_cp_mask_,XCHAL_CP1_IDENT);\r\n# endif\r\n# ifdef XCHAL_CP2_NAME\r\nextern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP2_IDENT);\r\nextern const unsigned int  XCJOIN(Xthal_cp_mask_,XCHAL_CP2_IDENT);\r\n# endif\r\n# ifdef XCHAL_CP3_NAME\r\nextern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP3_IDENT);\r\nextern const unsigned int  XCJOIN(Xthal_cp_mask_,XCHAL_CP3_IDENT);\r\n# endif\r\n# ifdef XCHAL_CP4_NAME\r\nextern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP4_IDENT);\r\nextern const unsigned int  XCJOIN(Xthal_cp_mask_,XCHAL_CP4_IDENT);\r\n# endif\r\n# ifdef XCHAL_CP5_NAME\r\nextern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP5_IDENT);\r\nextern const unsigned int  XCJOIN(Xthal_cp_mask_,XCHAL_CP5_IDENT);\r\n# endif\r\n# ifdef XCHAL_CP6_NAME\r\nextern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP6_IDENT);\r\nextern const unsigned int  XCJOIN(Xthal_cp_mask_,XCHAL_CP6_IDENT);\r\n# endif\r\n# ifdef XCHAL_CP7_NAME\r\nextern const unsigned char XCJOIN(Xthal_cp_id_,XCHAL_CP7_IDENT);\r\nextern const unsigned int  XCJOIN(Xthal_cp_mask_,XCHAL_CP7_IDENT);\r\n# endif\r\n#endif\r\n\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tDERIVED\r\n  ----------------------------------------------------------------------*/\r\n\r\n#if XCHAL_HAVE_BE\r\n#define XCHAL_INST_ILLN\t\t\t0xD60F\t\t/* 2-byte illegal instruction, msb-first */\r\n#define XCHAL_INST_ILLN_BYTE0\t\t0xD6\t\t/* 2-byte illegal instruction, 1st byte */\r\n#define XCHAL_INST_ILLN_BYTE1\t\t0x0F\t\t/* 2-byte illegal instruction, 2nd byte */\r\n#else\r\n#define XCHAL_INST_ILLN\t\t\t0xF06D\t\t/* 2-byte illegal instruction, lsb-first */\r\n#define XCHAL_INST_ILLN_BYTE0\t\t0x6D\t\t/* 2-byte illegal instruction, 1st byte */\r\n#define XCHAL_INST_ILLN_BYTE1\t\t0xF0\t\t/* 2-byte illegal instruction, 2nd byte */\r\n#endif\r\n/*  Belongs in xtensa/hal.h:  */\r\n#define XTHAL_INST_ILL\t\t\t0x000000\t/* 3-byte illegal instruction */\r\n\r\n\r\n/*\r\n *  Because information as to exactly which hardware version is targeted\r\n *  by a given software build is not always available, compile-time HAL\r\n *  Hardware-Release \"_AT\" macros are fuzzy (return 0, 1, or XCHAL_MAYBE):\r\n *  (Here \"RELEASE\" is now a misnomer; these are product *versions*, not the releases\r\n *   under which they are released.  In the T10##.# era there was no distinction.)\r\n */\r\n#if XCHAL_HW_CONFIGID_RELIABLE\r\n# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor)\t(XTHAL_REL_LE( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0)\r\n# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor)\t(XTHAL_REL_GE( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0)\r\n# define XCHAL_HW_RELEASE_AT(major,minor)\t\t(XTHAL_REL_EQ( XCHAL_HW_VERSION_MAJOR,XCHAL_HW_VERSION_MINOR, major,minor ) ? 1 : 0)\r\n# define XCHAL_HW_RELEASE_MAJOR_AT(major)\t\t((XCHAL_HW_VERSION_MAJOR == (major)) ? 1 : 0)\r\n#else\r\n# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor)\t( ((major) < 1040 && XCHAL_HAVE_XEA2) ? 0 \\\r\n\t\t\t\t\t\t\t: ((major) > 1050 && XCHAL_HAVE_XEA1) ? 1 \\\r\n\t\t\t\t\t\t\t: XTHAL_MAYBE )\r\n# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor)\t( ((major) >= 2000 && XCHAL_HAVE_XEA1) ? 0 \\\r\n\t\t\t\t\t\t\t: (XTHAL_REL_LE(major,minor, 1040,0) && XCHAL_HAVE_XEA2) ? 1 \\\r\n\t\t\t\t\t\t\t: XTHAL_MAYBE )\r\n# define XCHAL_HW_RELEASE_AT(major,minor)\t\t( (((major) < 1040 && XCHAL_HAVE_XEA2) || \\\r\n\t\t\t\t\t\t\t   ((major) >= 2000 && XCHAL_HAVE_XEA1)) ? 0 : XTHAL_MAYBE)\r\n# define XCHAL_HW_RELEASE_MAJOR_AT(major)\t\tXCHAL_HW_RELEASE_AT(major,0)\r\n#endif\r\n\r\n/*\r\n *  Specific errata:\r\n */\r\n\r\n/*\r\n *  Erratum T1020.H13, T1030.H7, T1040.H10, T1050.H4 (fixed in T1040.3 and T1050.1;\r\n *  relevant only in XEA1, kernel-vector mode, level-one interrupts and overflows enabled):\r\n */\r\n#define XCHAL_MAYHAVE_ERRATUM_XEA1KWIN\t(XCHAL_HAVE_XEA1 && \\\r\n\t\t\t\t\t (XCHAL_HW_RELEASE_AT_OR_BELOW(1040,2) != 0 \\\r\n\t\t\t\t\t  || XCHAL_HW_RELEASE_AT(1050,0)))\r\n\r\n\r\n\r\n#endif /*XTENSA_CONFIG_CORE_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/config/defs.h",
    "content": "/* Definitions for Xtensa instructions, types, and protos. */\r\n\r\n/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 2003-2004 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */\r\n\r\n/* NOTE: This file exists only for backward compatibility with T1050\r\n   and earlier Xtensa releases.  It includes only a subset of the\r\n   available header files.  */\r\n\r\n#ifndef _XTENSA_BASE_HEADER\r\n#define _XTENSA_BASE_HEADER\r\n\r\n#ifdef __XTENSA__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n#include <xtensa/tie/xt_misc.h>\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_BASE_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/config/specreg.h",
    "content": "/*\r\n * Xtensa Special Register symbolic names\r\n */\r\n\r\n/* $Id: //depot/rel/Boreal/Xtensa/SWConfig/hal/specreg.h.tpp#2 $ */\r\n\r\n/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 1998-2002 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */\r\n\r\n#ifndef XTENSA_SPECREG_H\r\n#define XTENSA_SPECREG_H\r\n\r\n/*  Include these special register bitfield definitions, for historical reasons:  */\r\n#include <xtensa/corebits.h>\r\n\r\n\r\n/*  Special registers:  */\r\n#define SAR\t\t3\r\n#define LITBASE\t\t5\r\n#define IBREAKENABLE\t96\r\n#define DDR\t\t104\r\n#define IBREAKA_0\t128\r\n#define DBREAKA_0\t144\r\n#define DBREAKC_0\t160\r\n#define EPC_1\t\t177\r\n#define EPC_2\t\t178\r\n#define EPC_3\t\t179\r\n#define DEPC\t\t192\r\n#define EPS_2\t\t194\r\n#define EPS_3\t\t195\r\n#define EXCSAVE_1\t209\r\n#define EXCSAVE_2\t210\r\n#define EXCSAVE_3\t211\r\n#define INTERRUPT\t226\r\n#define INTENABLE\t228\r\n#define PS\t\t230\r\n#define VECBASE\t\t231\r\n#define EXCCAUSE\t232\r\n#define DEBUGCAUSE\t233\r\n#define CCOUNT\t\t234\r\n#define PRID\t\t235\r\n#define ICOUNT\t\t236\r\n#define ICOUNTLEVEL\t237\r\n#define EXCVADDR\t238\r\n#define CCOMPARE_0\t240\r\n\r\n/*  Special cases (bases of special register series):  */\r\n#define IBREAKA\t\t128\r\n#define DBREAKA\t\t144\r\n#define DBREAKC\t\t160\r\n#define EPC\t\t176\r\n#define EPS\t\t192\r\n#define EXCSAVE\t\t208\r\n#define CCOMPARE\t240\r\n\r\n/*  Special names for read-only and write-only interrupt registers:  */\r\n#define INTREAD\t\t226\r\n#define INTSET\t\t226\r\n#define INTCLEAR\t227\r\n\r\n#endif /* XTENSA_SPECREG_H */\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/config/system.h",
    "content": "/* \r\n * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration\r\n *\r\n *  NOTE: The location and contents of this file are highly subject to change.\r\n *\r\n *  Source for configuration-independent binaries (which link in a\r\n *  configuration-specific HAL library) must NEVER include this file.\r\n *  The HAL itself has historically included this file in some instances,\r\n *  but this is not appropriate either, because the HAL is meant to be\r\n *  core-specific but system independent.\r\n */\r\n\r\n/* Customer ID=7011; Build=0x2b6f6; Copyright (c) 2000-2007 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */\r\n\r\n\r\n#ifndef XTENSA_CONFIG_SYSTEM_H\r\n#define XTENSA_CONFIG_SYSTEM_H\r\n\r\n/*#include <xtensa/hal.h>*/\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tCONFIGURED SOFTWARE OPTIONS\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XSHAL_USE_ABSOLUTE_LITERALS\t0\t/* (sw-only option, whether software uses absolute literals) */\r\n\r\n#define XSHAL_ABI\t\t\tXTHAL_ABI_CALL0\t/* (sw-only option, selected ABI) */\r\n/*  The above maps to one of the following constants:  */\r\n#define XTHAL_ABI_WINDOWED\t\t0\r\n#define XTHAL_ABI_CALL0\t\t\t1\r\n/*  Alternatives:  */\r\n/*#define XSHAL_WINDOWED_ABI\t\t0*/\t/* set if windowed ABI selected */\r\n/*#define XSHAL_CALL0_ABI\t\t1*/\t/* set if call0 ABI selected */\r\n\r\n#define XSHAL_CLIB\t\t\tXTHAL_CLIB_NEWLIB\t/* (sw-only option, selected C library) */\r\n/*  The above maps to one of the following constants:  */\r\n#define XTHAL_CLIB_NEWLIB\t\t0\r\n#define XTHAL_CLIB_UCLIBC\t\t1\r\n/*  Alternatives:  */\r\n/*#define XSHAL_NEWLIB\t\t\t1*/\t/* set if newlib C library selected */\r\n/*#define XSHAL_UCLIBC\t\t\t0*/\t/* set if uCLibC C library selected */\r\n\r\n#define XSHAL_USE_FLOATING_POINT\t1\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tDEVICE ADDRESSES\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*\r\n *  Strange place to find these, but the configuration GUI\r\n *  allows moving these around to account for various core\r\n *  configurations.  Specific boards (and their BSP software)\r\n *  will have specific meanings for these components.\r\n */\r\n\r\n/*  I/O Block areas:  */\r\n#define XSHAL_IOBLOCK_CACHED_VADDR\t0x70000000\r\n#define XSHAL_IOBLOCK_CACHED_PADDR\t0x70000000\r\n#define XSHAL_IOBLOCK_CACHED_SIZE\t0x0E000000\r\n\r\n#define XSHAL_IOBLOCK_BYPASS_VADDR\t0x90000000\r\n#define XSHAL_IOBLOCK_BYPASS_PADDR\t0x90000000\r\n#define XSHAL_IOBLOCK_BYPASS_SIZE\t0x0E000000\r\n\r\n/*  System ROM:  */\r\n#define XSHAL_ROM_VADDR\t\t0x50000000\r\n#define XSHAL_ROM_PADDR\t\t0x50000000\r\n#define XSHAL_ROM_SIZE\t\t0x01000000\r\n/*  Largest available area (free of vectors):  */\r\n#define XSHAL_ROM_AVAIL_VADDR\t0x50000300\r\n#define XSHAL_ROM_AVAIL_VSIZE\t0x00FFFD00\r\n\r\n/*  System RAM:  */\r\n#define XSHAL_RAM_VADDR\t\t0x60000000\r\n#define XSHAL_RAM_PADDR\t\t0x60000000\r\n#define XSHAL_RAM_VSIZE\t\t0x04000000\r\n#define XSHAL_RAM_PSIZE\t\t0x04000000\r\n#define XSHAL_RAM_SIZE\t\tXSHAL_RAM_PSIZE\r\n/*  Largest available area (free of vectors):  */\r\n#define XSHAL_RAM_AVAIL_VADDR\t0x60000000\r\n#define XSHAL_RAM_AVAIL_VSIZE\t0x04000000\r\n\r\n/*\r\n *  Shadow system RAM (same device as system RAM, at different address).\r\n *  (Emulation boards need this for the SONIC Ethernet driver\r\n *   when data caches are configured for writeback mode.)\r\n *  NOTE: on full MMU configs, this points to the BYPASS virtual address\r\n *  of system RAM, ie. is the same as XSHAL_RAM_* except that virtual\r\n *  addresses are viewed through the BYPASS static map rather than\r\n *  the CACHED static map.\r\n */\r\n#define XSHAL_RAM_BYPASS_VADDR\t\t0xA0000000\r\n#define XSHAL_RAM_BYPASS_PADDR\t\t0xA0000000\r\n#define XSHAL_RAM_BYPASS_PSIZE\t\t0x04000000\r\n\r\n/*  Alternate system RAM (different device than system RAM):  */\r\n/*#define XSHAL_ALTRAM_[VP]ADDR\t\t...not configured...*/\r\n/*#define XSHAL_ALTRAM_SIZE\t\t...not configured...*/\r\n\r\n/*  Some available location in which to place devices in a simulation (eg. XTMP):  */\r\n#define XSHAL_SIMIO_CACHED_VADDR\t0xC0000000\r\n#define XSHAL_SIMIO_BYPASS_VADDR\t0xC0000000\r\n#define XSHAL_SIMIO_PADDR\t\t0xC0000000\r\n#define XSHAL_SIMIO_SIZE\t\t0x20000000\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n *\t\t\tDEVICE-ADDRESS DEPENDENT...\r\n *\r\n *  Values written to CACHEATTR special register (or its equivalent)\r\n *  to enable and disable caches in various modes.\r\n *----------------------------------------------------------------------*/\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tBACKWARD COMPATIBILITY ...\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*\r\n *  NOTE:  the following two macros are DEPRECATED.  Use the latter\r\n *  board-specific macros instead, which are specially tuned for the\r\n *  particular target environments' memory maps.\r\n */\r\n#define XSHAL_CACHEATTR_BYPASS\t\tXSHAL_XT2000_CACHEATTR_BYPASS\t/* disable caches in bypass mode */\r\n#define XSHAL_CACHEATTR_DEFAULT\t\tXSHAL_XT2000_CACHEATTR_DEFAULT\t/* default setting to enable caches (no writeback!) */\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tGENERIC\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  For the following, a 512MB region is used if it contains a system (PIF) RAM,\r\n *  system (PIF) ROM, local memory, or XLMI.  */\r\n\r\n/*  These set any unused 512MB region to cache-BYPASS attribute:  */\r\n#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK\t0x22221112\t/* enable caches in write-back mode */\r\n#define XSHAL_ALLVALID_CACHEATTR_WRITEALLOC\t0x22221112\t/* enable caches in write-allocate mode */\r\n#define XSHAL_ALLVALID_CACHEATTR_WRITETHRU\t0x22221112\t/* enable caches in write-through mode */\r\n#define XSHAL_ALLVALID_CACHEATTR_BYPASS\t\t0x22222222\t/* disable caches in bypass mode */\r\n#define XSHAL_ALLVALID_CACHEATTR_DEFAULT\tXSHAL_ALLVALID_CACHEATTR_WRITEBACK\t/* default setting to enable caches */\r\n\r\n/*  These set any unused 512MB region to ILLEGAL attribute:  */\r\n#define XSHAL_STRICT_CACHEATTR_WRITEBACK\t0xFFFF111F\t/* enable caches in write-back mode */\r\n#define XSHAL_STRICT_CACHEATTR_WRITEALLOC\t0xFFFF111F\t/* enable caches in write-allocate mode */\r\n#define XSHAL_STRICT_CACHEATTR_WRITETHRU\t0xFFFF111F\t/* enable caches in write-through mode */\r\n#define XSHAL_STRICT_CACHEATTR_BYPASS\t\t0xFFFF222F\t/* disable caches in bypass mode */\r\n#define XSHAL_STRICT_CACHEATTR_DEFAULT\t\tXSHAL_STRICT_CACHEATTR_WRITEBACK\t/* default setting to enable caches */\r\n\r\n/*  These set the first 512MB, if unused, to ILLEGAL attribute to help catch\r\n *  NULL-pointer dereference bugs; all other unused 512MB regions are set\r\n *  to cache-BYPASS attribute:  */\r\n#define XSHAL_TRAPNULL_CACHEATTR_WRITEBACK\t0x2222111F\t/* enable caches in write-back mode */\r\n#define XSHAL_TRAPNULL_CACHEATTR_WRITEALLOC\t0x2222111F\t/* enable caches in write-allocate mode */\r\n#define XSHAL_TRAPNULL_CACHEATTR_WRITETHRU\t0x2222111F\t/* enable caches in write-through mode */\r\n#define XSHAL_TRAPNULL_CACHEATTR_BYPASS\t\t0x2222222F\t/* disable caches in bypass mode */\r\n#define XSHAL_TRAPNULL_CACHEATTR_DEFAULT\tXSHAL_TRAPNULL_CACHEATTR_WRITEBACK\t/* default setting to enable caches */\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tISS (Instruction Set Simulator) SPECIFIC ...\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  For now, ISS defaults to the TRAPNULL settings:  */\r\n#define XSHAL_ISS_CACHEATTR_WRITEBACK\tXSHAL_TRAPNULL_CACHEATTR_WRITEBACK\r\n#define XSHAL_ISS_CACHEATTR_WRITEALLOC\tXSHAL_TRAPNULL_CACHEATTR_WRITEALLOC\r\n#define XSHAL_ISS_CACHEATTR_WRITETHRU\tXSHAL_TRAPNULL_CACHEATTR_WRITETHRU\r\n#define XSHAL_ISS_CACHEATTR_BYPASS\tXSHAL_TRAPNULL_CACHEATTR_BYPASS\r\n#define XSHAL_ISS_CACHEATTR_DEFAULT\tXSHAL_TRAPNULL_CACHEATTR_WRITEBACK\r\n\r\n#define XSHAL_ISS_PIPE_REGIONS\t0\r\n#define XSHAL_ISS_SDRAM_REGIONS\t0\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tXT2000 BOARD SPECIFIC ...\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  For the following, a 512MB region is used if it contains any system RAM,\r\n *  system ROM, local memory, XLMI, or other XT2000 board device or memory.\r\n *  Regions containing devices are forced to cache-BYPASS mode regardless\r\n *  of whether the macro is _WRITEBACK vs. _BYPASS etc.  */\r\n\r\n/*  These set any 512MB region unused on the XT2000 to ILLEGAL attribute:  */\r\n#define XSHAL_XT2000_CACHEATTR_WRITEBACK\t0xFF22111F\t/* enable caches in write-back mode */\r\n#define XSHAL_XT2000_CACHEATTR_WRITEALLOC\t0xFF22111F\t/* enable caches in write-allocate mode */\r\n#define XSHAL_XT2000_CACHEATTR_WRITETHRU\t0xFF22111F\t/* enable caches in write-through mode */\r\n#define XSHAL_XT2000_CACHEATTR_BYPASS\t\t0xFF22222F\t/* disable caches in bypass mode */\r\n#define XSHAL_XT2000_CACHEATTR_DEFAULT\t\tXSHAL_XT2000_CACHEATTR_WRITEBACK\t/* default setting to enable caches */\r\n\r\n#define XSHAL_XT2000_PIPE_REGIONS\t0x00000000\t/* BusInt pipeline regions */\r\n#define XSHAL_XT2000_SDRAM_REGIONS\t0x00000440\t/* BusInt SDRAM regions */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tVECTOR INFO AND SIZES\r\n  ----------------------------------------------------------------------*/\r\n\r\n#define XSHAL_VECTORS_PACKED\t\t0\r\n#define XSHAL_STATIC_VECTOR_SELECT\t0\r\n#define XSHAL_RESET_VECTOR_VADDR\t0x50000000\r\n#define XSHAL_RESET_VECTOR_PADDR\t0x50000000\r\n\r\n/*\r\n *  Sizes allocated to vectors by the system (memory map) configuration.\r\n *  These sizes are constrained by core configuration (eg. one vector's\r\n *  code cannot overflow into another vector) but are dependent on the\r\n *  system or board (or LSP) memory map configuration.\r\n *\r\n *  Whether or not each vector happens to be in a system ROM is also\r\n *  a system configuration matter, sometimes useful, included here also:\r\n */\r\n#define XSHAL_RESET_VECTOR_SIZE\t0x00000300\r\n#define XSHAL_RESET_VECTOR_ISROM\t1\r\n#define XSHAL_USER_VECTOR_SIZE\t0x0000001C\r\n#define XSHAL_USER_VECTOR_ISROM\t0\r\n#define XSHAL_PROGRAMEXC_VECTOR_SIZE\tXSHAL_USER_VECTOR_SIZE\t/* for backward compatibility */\r\n#define XSHAL_USEREXC_VECTOR_SIZE\tXSHAL_USER_VECTOR_SIZE\t/* for backward compatibility */\r\n#define XSHAL_KERNEL_VECTOR_SIZE\t0x0000001C\r\n#define XSHAL_KERNEL_VECTOR_ISROM\t0\r\n#define XSHAL_STACKEDEXC_VECTOR_SIZE\tXSHAL_KERNEL_VECTOR_SIZE\t/* for backward compatibility */\r\n#define XSHAL_KERNELEXC_VECTOR_SIZE\tXSHAL_KERNEL_VECTOR_SIZE\t/* for backward compatibility */\r\n#define XSHAL_DOUBLEEXC_VECTOR_SIZE\t0x00000010\r\n#define XSHAL_DOUBLEEXC_VECTOR_ISROM\t0\r\n#define XSHAL_INTLEVEL2_VECTOR_SIZE\t0x0000000C\r\n#define XSHAL_INTLEVEL2_VECTOR_ISROM\t0\r\n#define XSHAL_DEBUG_VECTOR_SIZE\t\tXSHAL_INTLEVEL2_VECTOR_SIZE\r\n#define XSHAL_DEBUG_VECTOR_ISROM\tXSHAL_INTLEVEL2_VECTOR_ISROM\r\n#define XSHAL_NMI_VECTOR_SIZE\t0x0000000C\r\n#define XSHAL_NMI_VECTOR_ISROM\t0\r\n#define XSHAL_INTLEVEL3_VECTOR_SIZE\tXSHAL_NMI_VECTOR_SIZE\r\n\r\n\r\n#endif /*XTENSA_CONFIG_SYSTEM_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/config/tie-asm.h",
    "content": "/* \r\n * tie-asm.h -- compile-time HAL assembler definitions dependent on CORE & TIE\r\n *\r\n *  NOTE:  This header file is not meant to be included directly.\r\n */\r\n\r\n/* This header file contains assembly-language definitions (assembly\r\n   macros, etc.) for this specific Xtensa processor's TIE extensions\r\n   and options.  It is customized to this Xtensa processor configuration.\r\n\r\n   Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */\r\n\r\n#ifndef _XTENSA_CORE_TIE_ASM_H\r\n#define _XTENSA_CORE_TIE_ASM_H\r\n\r\n/*  Selection parameter values for save-area save/restore macros:  */\r\n/*  Option vs. TIE:  */\r\n#define XTHAL_SAS_TIE\t0x0001\t/* custom extension or coprocessor */\r\n#define XTHAL_SAS_OPT\t0x0002\t/* optional (and not a coprocessor) */\r\n/*  Whether used automatically by compiler:  */\r\n#define XTHAL_SAS_NOCC\t0x0004\t/* not used by compiler w/o special opts/code */\r\n#define XTHAL_SAS_CC\t0x0008\t/* used by compiler without special opts/code */\r\n/*  ABI handling across function calls:  */\r\n#define XTHAL_SAS_CALR\t0x0010\t/* caller-saved */\r\n#define XTHAL_SAS_CALE\t0x0020\t/* callee-saved */\r\n#define XTHAL_SAS_GLOB\t0x0040\t/* global across function calls (in thread) */\r\n/*  Misc  */\r\n#define XTHAL_SAS_ALL\t0xFFFF\t/* include all default NCP contents */\r\n\r\n\r\n\r\n/* Macro to save all non-coprocessor (extra) custom TIE and optional state\r\n * (not including zero-overhead loop registers).\r\n * Save area ptr (clobbered):  ptr  (1 byte aligned)\r\n * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_NCP_NUM_ATMPS needed)\r\n */\r\n\t.macro xchal_ncp_store  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL\r\n\txchal_sa_start\t\\continue, \\ofs\r\n\t.endm\t// xchal_ncp_store\r\n\r\n/* Macro to save all non-coprocessor (extra) custom TIE and optional state\r\n * (not including zero-overhead loop registers).\r\n * Save area ptr (clobbered):  ptr  (1 byte aligned)\r\n * Scratch regs  (clobbered):  at1..at4  (only first XCHAL_NCP_NUM_ATMPS needed)\r\n */\r\n\t.macro xchal_ncp_load  ptr at1 at2 at3 at4  continue=0 ofs=-1 select=XTHAL_SAS_ALL\r\n\txchal_sa_start\t\\continue, \\ofs\r\n\t.endm\t// xchal_ncp_load\r\n\r\n\r\n\r\n#define XCHAL_NCP_NUM_ATMPS\t0\r\n\r\n\r\n#define XCHAL_SA_NUM_ATMPS\t0\r\n\r\n#endif /*_XTENSA_CORE_TIE_ASM_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/config/tie.h",
    "content": "/* \r\n * tie.h -- compile-time HAL definitions dependent on CORE & TIE configuration\r\n *\r\n *  NOTE:  This header file is not meant to be included directly.\r\n */\r\n\r\n/* This header file describes this specific Xtensa processor's TIE extensions\r\n   that extend basic Xtensa core functionality.  It is customized to this\r\n   Xtensa processor configuration.\r\n\r\n   Customer ID=7011; Build=0x2b6f6; Copyright (c) 1999-2010 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */\r\n\r\n#ifndef _XTENSA_CORE_TIE_H\r\n#define _XTENSA_CORE_TIE_H\r\n\r\n#define XCHAL_CP_NUM\t\t\t0\t/* number of coprocessors */\r\n#define XCHAL_CP_MAX\t\t\t0\t/* max CP ID + 1 (0 if none) */\r\n#define XCHAL_CP_MASK\t\t\t0x00\t/* bitmask of all CPs by ID */\r\n#define XCHAL_CP_PORT_MASK\t\t0x00\t/* bitmask of only port CPs */\r\n\r\n/*  Save area for non-coprocessor optional and custom (TIE) state:  */\r\n#define XCHAL_NCP_SA_SIZE\t\t0\r\n#define XCHAL_NCP_SA_ALIGN\t\t1\r\n\r\n/*  Total save area for optional and custom state (NCP + CPn):  */\r\n#define XCHAL_TOTAL_SA_SIZE\t\t0\t/* with 16-byte align padding */\r\n#define XCHAL_TOTAL_SA_ALIGN\t\t1\t/* actual minimum alignment */\r\n\r\n/*\r\n * Detailed contents of save areas.\r\n * NOTE:  caller must define the XCHAL_SA_REG macro (not defined here)\r\n * before expanding the XCHAL_xxx_SA_LIST() macros.\r\n *\r\n * XCHAL_SA_REG(s,ccused,abikind,kind,opt,name,galign,align,asize,\r\n *\t\tdbnum,base,regnum,bitsz,gapsz,reset,x...)\r\n *\r\n *\ts = passed from XCHAL_*_LIST(s), eg. to select how to expand\r\n *\tccused = set if used by compiler without special options or code\r\n *\tabikind = 0 (caller-saved), 1 (callee-saved), or 2 (thread-global)\r\n *\tkind = 0 (special reg), 1 (TIE user reg), or 2 (TIE regfile reg)\r\n *\topt = 0 (custom TIE extension or coprocessor), or 1 (optional reg)\r\n *\tname = lowercase reg name (no quotes)\r\n *\tgalign = group byte alignment (power of 2) (galign >= align)\r\n *\talign = register byte alignment (power of 2)\r\n *\tasize = allocated size in bytes (asize*8 == bitsz + gapsz + padsz)\r\n *\t  (not including any pad bytes required to galign this or next reg)\r\n *\tdbnum = unique target number f/debug (see <xtensa-libdb-macros.h>)\r\n *\tbase = reg shortname w/o index (or sr=special, ur=TIE user reg)\r\n *\tregnum = reg index in regfile, or special/TIE-user reg number\r\n *\tbitsz = number of significant bits (regfile width, or ur/sr mask bits)\r\n *\tgapsz = intervening bits, if bitsz bits not stored contiguously\r\n *\t(padsz = pad bits at end [TIE regfile] or at msbits [ur,sr] of asize)\r\n *\treset = register reset value (or 0 if undefined at reset)\r\n *\tx = reserved for future use (0 until then)\r\n *\r\n *  To filter out certain registers, e.g. to expand only the non-global\r\n *  registers used by the compiler, you can do something like this:\r\n *\r\n *  #define XCHAL_SA_REG(s,ccused,p...)\tSELCC##ccused(p)\r\n *  #define SELCC0(p...)\r\n *  #define SELCC1(abikind,p...)\tSELAK##abikind(p)\r\n *  #define SELAK0(p...)\t\tREG(p)\r\n *  #define SELAK1(p...)\t\tREG(p)\r\n *  #define SELAK2(p...)\r\n *  #define REG(kind,tie,name,galn,aln,asz,csz,dbnum,base,rnum,bsz,rst,x...) \\\r\n *\t\t...what you want to expand...\r\n */\r\n\r\n#define XCHAL_NCP_SA_NUM\t0\r\n#define XCHAL_NCP_SA_LIST(s)\t/* empty */\r\n\r\n#define XCHAL_CP0_SA_NUM\t0\r\n#define XCHAL_CP0_SA_LIST(s)\t/* empty */\r\n\r\n#define XCHAL_CP1_SA_NUM\t0\r\n#define XCHAL_CP1_SA_LIST(s)\t/* empty */\r\n\r\n#define XCHAL_CP2_SA_NUM\t0\r\n#define XCHAL_CP2_SA_LIST(s)\t/* empty */\r\n\r\n#define XCHAL_CP3_SA_NUM\t0\r\n#define XCHAL_CP3_SA_LIST(s)\t/* empty */\r\n\r\n#define XCHAL_CP4_SA_NUM\t0\r\n#define XCHAL_CP4_SA_LIST(s)\t/* empty */\r\n\r\n#define XCHAL_CP5_SA_NUM\t0\r\n#define XCHAL_CP5_SA_LIST(s)\t/* empty */\r\n\r\n#define XCHAL_CP6_SA_NUM\t0\r\n#define XCHAL_CP6_SA_LIST(s)\t/* empty */\r\n\r\n#define XCHAL_CP7_SA_NUM\t0\r\n#define XCHAL_CP7_SA_LIST(s)\t/* empty */\r\n\r\n/* Byte length of instruction from its first nibble (op0 field), per FLIX.  */\r\n#define XCHAL_OP0_FORMAT_LENGTHS\t3,3,3,3,3,3,3,3,2,2,2,2,2,2,3,3\r\n\r\n#endif /*_XTENSA_CORE_TIE_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/coreasm.h",
    "content": "/*\r\n * xtensa/coreasm.h -- assembler-specific definitions that depend on CORE configuration\r\n *\r\n *  Source for configuration-independent binaries (which link in a\r\n *  configuration-specific HAL library) must NEVER include this file.\r\n *  It is perfectly normal, however, for the HAL itself to include this file.\r\n *\r\n *  This file must NOT include xtensa/config/system.h.  Any assembler\r\n *  header file that depends on system information should likely go\r\n *  in a new systemasm.h (or sysasm.h) header file.\r\n *\r\n *  NOTE: macro beqi32 is NOT configuration-dependent, and is placed\r\n *        here until we have a proper configuration-independent header file.\r\n */\r\n\r\n/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/coreasm.h#2 $ */\r\n\r\n/*\r\n * Copyright (c) 2000-2007 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef XTENSA_COREASM_H\r\n#define XTENSA_COREASM_H\r\n\r\n/*\r\n *  Tell header files this is assembly source, so they can avoid non-assembler\r\n *  definitions (eg. C types etc):\r\n */\r\n#ifndef _ASMLANGUAGE\t/* conditionalize to avoid cpp warnings (3rd parties might use same macro) */\r\n#define _ASMLANGUAGE\r\n#endif\r\n\r\n#include <xtensa/config/core.h>\r\n#include <xtensa/config/specreg.h>\r\n\r\n/*\r\n *  Assembly-language specific definitions (assembly macros, etc.).\r\n */\r\n\r\n/*----------------------------------------------------------------------\r\n *  find_ms_setbit\r\n *\r\n *  This macro finds the most significant bit that is set in <as>\r\n *  and return its index + <base> in <ad>, or <base> - 1 if <as> is zero.\r\n *  The index counts starting at zero for the lsbit, so the return\r\n *  value ranges from <base>-1 (no bit set) to <base>+31 (msbit set).\r\n *\r\n *  Parameters:\r\n *\t<ad>\tdestination address register (any register)\r\n *\t<as>\tsource address register\r\n *\t<at>\ttemporary address register (must be different than <as>)\r\n *\t<base>\tconstant value added to result (usually 0 or 1)\r\n *  On entry:\r\n *\t<ad> = undefined if different than <as>\r\n *\t<as> = value whose most significant set bit is to be found\r\n *\t<at> = undefined\r\n *\tno other registers are used by this macro.\r\n *  On exit:\r\n *\t<ad> = <base> + index of msbit set in original <as>,\r\n *\t     = <base> - 1 if original <as> was zero.\r\n *\t<as> clobbered (if not <ad>)\r\n *\t<at> clobbered (if not <ad>)\r\n *  Example:\r\n *\tfind_ms_setbit a0, a4, a0, 0\t\t-- return in a0 index of msbit set in a4\r\n */\r\n\r\n\t.macro\tfind_ms_setbit ad, as, at, base\r\n#if XCHAL_HAVE_NSA\r\n\tmovi\t\\at, 31+\\base\r\n\tnsau\t\\as, \\as\t// get index of \\as, numbered from msbit (32 if absent)\r\n\tsub\t\\ad, \\at, \\as\t// get numbering from lsbit (0..31, -1 if absent)\r\n#else /* XCHAL_HAVE_NSA */\r\n\tmovi\t\\at, \\base\t// start with result of 0 (point to lsbit of 32)\r\n\r\n\tbeqz\t\\as, 2f\t\t// special case for zero argument: return -1\r\n\tbltui\t\\as, 0x10000, 1f\t// is it one of the 16 lsbits? (if so, check lower 16 bits)\r\n\taddi\t\\at, \\at, 16\t// no, increment result to upper 16 bits (of 32)\r\n\t//srli\t\\as, \\as, 16\t// check upper half (shift right 16 bits)\r\n\textui\t\\as, \\as, 16, 16\t// check upper half (shift right 16 bits)\r\n1:\tbltui\t\\as, 0x100, 1f\t// is it one of the 8 lsbits? (if so, check lower 8 bits)\r\n\taddi\t\\at, \\at, 8\t// no, increment result to upper 8 bits (of 16)\r\n\tsrli\t\\as, \\as, 8\t// shift right to check upper 8 bits\r\n1:\tbltui\t\\as, 0x10, 1f\t// is it one of the 4 lsbits? (if so, check lower 4 bits)\r\n\taddi\t\\at, \\at, 4\t// no, increment result to upper 4 bits (of 8)\r\n\tsrli\t\\as, \\as, 4\t// shift right 4 bits to check upper half\r\n1:\tbltui\t\\as, 0x4, 1f\t// is it one of the 2 lsbits? (if so, check lower 2 bits)\r\n\taddi\t\\at, \\at, 2\t// no, increment result to upper 2 bits (of 4)\r\n\tsrli\t\\as, \\as, 2\t// shift right 2 bits to check upper half\r\n1:\tbltui\t\\as, 0x2, 1f\t// is it the lsbit?\r\n\taddi\t\\at, \\at, 2\t// no, increment result to upper bit (of 2)\r\n2:\taddi\t\\at, \\at, -1\t// (from just above: add 1;  from beqz: return -1)\r\n\t//srli\t\\as, \\as, 1\r\n1:\t\t\t\t// done! \\at contains index of msbit set (or -1 if none set)\r\n\t.if\t0x\\ad - 0x\\at\t// destination different than \\at ? (works because regs are a0-a15)\r\n\tmov\t\\ad, \\at\t// then move result to \\ad\r\n\t.endif\r\n#endif /* XCHAL_HAVE_NSA */\r\n\t.endm\t// find_ms_setbit\r\n\r\n/*----------------------------------------------------------------------\r\n *  find_ls_setbit\r\n *\r\n *  This macro finds the least significant bit that is set in <as>,\r\n *  and return its index in <ad>.\r\n *  Usage is the same as for the find_ms_setbit macro.\r\n *  Example:\r\n *\tfind_ls_setbit a0, a4, a0, 0\t-- return in a0 index of lsbit set in a4\r\n */\r\n\r\n\t.macro\tfind_ls_setbit ad, as, at, base\r\n\tneg\t\\at, \\as\t// keep only the least-significant bit that is set...\r\n\tand\t\\as, \\at, \\as\t// ... in \\as\r\n\tfind_ms_setbit\t\\ad, \\as, \\at, \\base\r\n\t.endm\t// find_ls_setbit\r\n\r\n/*----------------------------------------------------------------------\r\n *  find_ls_one\r\n *\r\n *  Same as find_ls_setbit with base zero.\r\n *  Source (as) and destination (ad) registers must be different.\r\n *  Provided for backward compatibility.\r\n */\r\n\r\n\t.macro\tfind_ls_one ad, as\r\n\tfind_ls_setbit\t\\ad, \\as, \\ad, 0\r\n\t.endm\t// find_ls_one\r\n\r\n/*----------------------------------------------------------------------\r\n *  floop, floopnez, floopgtz, floopend\r\n *\r\n *  These macros are used for fast inner loops that\r\n *  work whether or not the Loops options is configured.\r\n *  If the Loops option is configured, they simply use\r\n *  the zero-overhead LOOP instructions; otherwise\r\n *  they use explicit decrement and branch instructions.\r\n *\r\n *  They are used in pairs, with floop, floopnez or floopgtz\r\n *  at the beginning of the loop, and floopend at the end.\r\n *\r\n *  Each pair of loop macro calls must be given the loop count\r\n *  address register and a unique label for that loop.\r\n *\r\n *  Example:\r\n *\r\n *\tmovi\t a3, 16     // loop 16 times\r\n *\tfloop    a3, myloop1\r\n *\t:\r\n *\tbnez     a7, end1\t// exit loop if a7 != 0\r\n *\t:\r\n *\tfloopend a3, myloop1\r\n *  end1:\r\n *\r\n *  Like the LOOP instructions, these macros cannot be\r\n *  nested, must include at least one instruction,\r\n *  cannot call functions inside the loop, etc.\r\n *  The loop can be exited by jumping to the instruction\r\n *  following floopend (or elsewhere outside the loop),\r\n *  or continued by jumping to a NOP instruction placed\r\n *  immediately before floopend.\r\n *\r\n *  Unlike LOOP instructions, the register passed to floop*\r\n *  cannot be used inside the loop, because it is used as\r\n *  the loop counter if the Loops option is not configured.\r\n *  And its value is undefined after exiting the loop.\r\n *  And because the loop counter register is active inside\r\n *  the loop, you can't easily use this construct to loop\r\n *  across a register file using ROTW as you might with LOOP\r\n *  instructions, unless you copy the loop register along.\r\n */\r\n\r\n\t/*  Named label version of the macros:  */\r\n\r\n\t.macro\tfloop\t\tar, endlabel\r\n\tfloop_\t\t\\ar, .Lfloopstart_\\endlabel, .Lfloopend_\\endlabel\r\n\t.endm\r\n\r\n\t.macro\tfloopnez\tar, endlabel\r\n\tfloopnez_\t\\ar, .Lfloopstart_\\endlabel, .Lfloopend_\\endlabel\r\n\t.endm\r\n\r\n\t.macro\tfloopgtz\tar, endlabel\r\n\tfloopgtz_\t\\ar, .Lfloopstart_\\endlabel, .Lfloopend_\\endlabel\r\n\t.endm\r\n\r\n\t.macro\tfloopend\tar, endlabel\r\n\tfloopend_\t\\ar, .Lfloopstart_\\endlabel, .Lfloopend_\\endlabel\r\n\t.endm\r\n\r\n\t/*  Numbered local label version of the macros:  */\r\n#if 0 /*UNTESTED*/\r\n\t.macro\tfloop89\t\tar\r\n\tfloop_\t\t\\ar, 8, 9f\r\n\t.endm\r\n\r\n\t.macro\tfloopnez89\tar\r\n\tfloopnez_\t\\ar, 8, 9f\r\n\t.endm\r\n\r\n\t.macro\tfloopgtz89\tar\r\n\tfloopgtz_\t\\ar, 8, 9f\r\n\t.endm\r\n\r\n\t.macro\tfloopend89\tar\r\n\tfloopend_\t\\ar, 8b, 9\r\n\t.endm\r\n#endif /*0*/\r\n\r\n\t/*  Underlying version of the macros:  */\r\n\r\n\t.macro\tfloop_\tar, startlabel, endlabelref\r\n\t.ifdef\t_infloop_\r\n\t.if\t_infloop_\r\n\t.err\t// Error: floop cannot be nested\r\n\t.endif\r\n\t.endif\r\n\t.set\t_infloop_, 1\r\n#if XCHAL_HAVE_LOOPS\r\n\tloop\t\\ar, \\endlabelref\r\n#else /* XCHAL_HAVE_LOOPS */\r\n\\startlabel:\r\n\taddi\t\\ar, \\ar, -1\r\n#endif /* XCHAL_HAVE_LOOPS */\r\n\t.endm\t// floop_\r\n\r\n\t.macro\tfloopnez_\tar, startlabel, endlabelref\r\n\t.ifdef\t_infloop_\r\n\t.if\t_infloop_\r\n\t.err\t// Error: floopnez cannot be nested\r\n\t.endif\r\n\t.endif\r\n\t.set\t_infloop_, 1\r\n#if XCHAL_HAVE_LOOPS\r\n\tloopnez\t\\ar, \\endlabelref\r\n#else /* XCHAL_HAVE_LOOPS */\r\n\tbeqz\t\\ar, \\endlabelref\r\n\\startlabel:\r\n\taddi\t\\ar, \\ar, -1\r\n#endif /* XCHAL_HAVE_LOOPS */\r\n\t.endm\t// floopnez_\r\n\r\n\t.macro\tfloopgtz_\tar, startlabel, endlabelref\r\n\t.ifdef\t_infloop_\r\n\t.if\t_infloop_\r\n\t.err\t// Error: floopgtz cannot be nested\r\n\t.endif\r\n\t.endif\r\n\t.set\t_infloop_, 1\r\n#if XCHAL_HAVE_LOOPS\r\n\tloopgtz\t\\ar, \\endlabelref\r\n#else /* XCHAL_HAVE_LOOPS */\r\n\tbltz\t\\ar, \\endlabelref\r\n\tbeqz\t\\ar, \\endlabelref\r\n\\startlabel:\r\n\taddi\t\\ar, \\ar, -1\r\n#endif /* XCHAL_HAVE_LOOPS */\r\n\t.endm\t// floopgtz_\r\n\r\n\r\n\t.macro\tfloopend_\tar, startlabelref, endlabel\r\n\t.ifndef\t_infloop_\r\n\t.err\t// Error: floopend without matching floopXXX\r\n\t.endif\r\n\t.ifeq\t_infloop_\r\n\t.err\t// Error: floopend without matching floopXXX\r\n\t.endif\r\n\t.set\t_infloop_, 0\r\n#if ! XCHAL_HAVE_LOOPS\r\n\tbnez\t\\ar, \\startlabelref\r\n#endif /* XCHAL_HAVE_LOOPS */\r\n\\endlabel:\r\n\t.endm\t// floopend_\r\n\r\n/*----------------------------------------------------------------------\r\n *  crsil  --  conditional RSIL (read/set interrupt level)\r\n *\r\n *  Executes the RSIL instruction if it exists, else just reads PS.\r\n *  The RSIL instruction does not exist in the new exception architecture\r\n *  if the interrupt option is not selected.\r\n */\r\n\r\n\t.macro\tcrsil\tar, newlevel\r\n#if XCHAL_HAVE_OLD_EXC_ARCH || XCHAL_HAVE_INTERRUPTS\r\n\trsil\t\\ar, \\newlevel\r\n#else\r\n\trsr\t\\ar, PS\r\n#endif\r\n\t.endm\t// crsil\r\n\r\n/*----------------------------------------------------------------------\r\n *  safe_movi_a0  --  move constant into a0 when L32R is not safe\r\n *\r\n *  This macro is typically used by interrupt/exception handlers.\r\n *  Loads a 32-bit constant in a0, without using any other register,\r\n *  and without corrupting the LITBASE register, even when the\r\n *  value of the LITBASE register is unknown (eg. when application\r\n *  code and interrupt/exception handling code are built independently,\r\n *  and thus with independent values of the LITBASE register;\r\n *  debug monitors are one example of this).\r\n *\r\n *  Worst-case size of resulting code:  17 bytes.\r\n */\r\n\r\n\t.macro\tsafe_movi_a0\tconstant\r\n#if XCHAL_HAVE_ABSOLUTE_LITERALS\r\n\t/*  Contort a PC-relative literal load even though we may be in litbase-relative mode: */\r\n\tj\t1f\r\n\t.begin\tno-transform\t\t\t// ensure what follows is assembled exactly as-is\r\n\t.align\t4\t\t\t\t// ensure constant and call0 target ...\r\n\t.byte\t0\t\t\t\t// ... are 4-byte aligned (call0 instruction is 3 bytes long)\r\n1:\tcall0\t2f\t\t\t\t// read PC (that follows call0) in a0\r\n\t.long\t\\constant\t\t\t// 32-bit constant to load into a0\r\n2:\r\n\t.end\tno-transform\r\n\tl32i\ta0, a0, 0\t\t\t// load constant\r\n#else\r\n\tmovi\ta0, \\constant\t\t\t// no LITBASE, can assume PC-relative L32R\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n *  window_spill{4,8,12}\r\n *\r\n *  These macros spill callers' register windows to the stack.\r\n *  They work for both privileged and non-privileged tasks.\r\n *  Must be called from a windowed ABI context, eg. within\r\n *  a windowed ABI function (ie. valid stack frame, window\r\n *  exceptions enabled, not in exception mode, etc).\r\n *\r\n *  This macro requires a single invocation of the window_spill_common\r\n *  macro in the same assembly unit and section.\r\n *\r\n *  Note that using window_spill{4,8,12} macros is more efficient\r\n *  than calling a function implemented using window_spill_function,\r\n *  because the latter needs extra code to figure out the size of\r\n *  the call to the spilling function.\r\n *\r\n *  Example usage:\r\n *\t\r\n *\t\t.text\r\n *\t\t.align\t4\r\n *\t\t.global\tsome_function\r\n *\t\t.type\tsome_function,@function\r\n *\tsome_function:\r\n *\t\tentry\ta1, 16\r\n *\t\t:\r\n *\t\t:\r\n *\r\n *\t\twindow_spill4\t// Spill windows of some_function's callers; preserves a0..a3 only;\r\n *\t\t\t\t// to use window_spill{8,12} in this example function we'd have\r\n *\t\t\t\t// to increase space allocated by the entry instruction, because\r\n *\t\t\t\t// 16 bytes only allows call4; 32 or 48 bytes (+locals) are needed\r\n *\t\t\t\t// for call8/window_spill8 or call12/window_spill12 respectively.\r\n *\r\n *\t\t:\r\n *\r\n *\t\tretw\r\n *\r\n *\t\twindow_spill_common\t// instantiates code used by window_spill4\r\n *\r\n *\r\n *  On entry:\r\n *\tnone (if window_spill4)\r\n *\tstack frame has enough space allocated for call8 (if window_spill8)\r\n *\tstack frame has enough space allocated for call12 (if window_spill12)\r\n *  On exit:\r\n *\t a4..a15 clobbered (if window_spill4)\r\n *\t a8..a15 clobbered (if window_spill8)\r\n *\ta12..a15 clobbered (if window_spill12)\r\n *\tno caller windows are in live registers\r\n */\r\n\r\n\t.macro\twindow_spill4\r\n#if XCHAL_HAVE_WINDOWED\r\n# if XCHAL_NUM_AREGS == 16\r\n\tmovi\ta15, 0\t\t\t// for 16-register files, no need to call to reach the end\r\n# elif XCHAL_NUM_AREGS == 32\r\n\tcall4\t.L__wdwspill_assist28\t// call deep enough to clear out any live callers\r\n# elif XCHAL_NUM_AREGS == 64\r\n\tcall4\t.L__wdwspill_assist60\t// call deep enough to clear out any live callers\r\n# endif\r\n#endif\r\n\t.endm\t// window_spill4\r\n\r\n\t.macro\twindow_spill8\r\n#if XCHAL_HAVE_WINDOWED\r\n# if XCHAL_NUM_AREGS == 16\r\n\tmovi\ta15, 0\t\t\t// for 16-register files, no need to call to reach the end\r\n# elif XCHAL_NUM_AREGS == 32\r\n\tcall8\t.L__wdwspill_assist24\t// call deep enough to clear out any live callers\r\n# elif XCHAL_NUM_AREGS == 64\r\n\tcall8\t.L__wdwspill_assist56\t// call deep enough to clear out any live callers\r\n# endif\r\n#endif\r\n\t.endm\t// window_spill8\r\n\r\n\t.macro\twindow_spill12\r\n#if XCHAL_HAVE_WINDOWED\r\n# if XCHAL_NUM_AREGS == 16\r\n\tmovi\ta15, 0\t\t\t// for 16-register files, no need to call to reach the end\r\n# elif XCHAL_NUM_AREGS == 32\r\n\tcall12\t.L__wdwspill_assist20\t// call deep enough to clear out any live callers\r\n# elif XCHAL_NUM_AREGS == 64\r\n\tcall12\t.L__wdwspill_assist52\t// call deep enough to clear out any live callers\r\n# endif\r\n#endif\r\n\t.endm\t// window_spill12\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n *  window_spill_function\r\n *\r\n *  This macro outputs a function that will spill its caller's callers'\r\n *  register windows to the stack.  Eg. it could be used to implement\r\n *  a version of xthal_window_spill() that works in non-privileged tasks.\r\n *  This works for both privileged and non-privileged tasks.\r\n *\r\n *  Typical usage:\r\n *\r\n *\t\t.text\r\n *\t\t.align\t4\r\n *\t\t.global\tmy_spill_function\r\n *\t\t.type\tmy_spill_function,@function\r\n *\tmy_spill_function:\r\n *\t\twindow_spill_function\r\n *\r\n *  On entry to resulting function:\r\n *\tnone\r\n *  On exit from resulting function:\r\n *\tnone (no caller windows are in live registers)\r\n */\r\n\r\n\t.macro\twindow_spill_function\r\n#if XCHAL_HAVE_WINDOWED\r\n#  if XCHAL_NUM_AREGS == 32\r\n\tentry\tsp, 48\r\n\tbbci.l\ta0, 31, 1f\t\t// branch if called with call4\r\n\tbbsi.l\ta0, 30, 2f\t\t// branch if called with call12\r\n\tcall8\t.L__wdwspill_assist16\t// called with call8, only need another 8\r\n\tretw\r\n1:\tcall12\t.L__wdwspill_assist16\t// called with call4, only need another 12\r\n\tretw\r\n2:\tcall4\t.L__wdwspill_assist16\t// called with call12, only need another 4\r\n\tretw\r\n#  elif XCHAL_NUM_AREGS == 64\r\n\tentry\tsp, 48\r\n\tbbci.l\ta0, 31, 1f\t\t// branch if called with call4\r\n\tbbsi.l\ta0, 30, 2f\t\t// branch if called with call12\r\n\tcall4\t.L__wdwspill_assist52\t// called with call8, only need a call4\r\n\tretw\r\n1:\tcall8\t.L__wdwspill_assist52\t// called with call4, only need a call8\r\n\tretw\r\n2:\tcall12\t.L__wdwspill_assist40\t// called with call12, can skip a call12\r\n\tretw\r\n#  elif XCHAL_NUM_AREGS == 16\r\n\tentry\tsp, 16\r\n\tbbci.l\ta0, 31, 1f\t// branch if called with call4\r\n\tbbsi.l\ta0, 30, 2f\t// branch if called with call12\r\n\tmovi\ta7, 0\t\t// called with call8\r\n\tretw\r\n1:\tmovi\ta11, 0\t\t// called with call4\r\n2:\tretw\t\t\t// if called with call12, everything already spilled\r\n\r\n//\tmovi\ta15, 0\t\t// trick to spill all but the direct caller\r\n//\tj\t1f\r\n//\t//  The entry instruction is magical in the assembler (gets auto-aligned)\r\n//\t//  so we have to jump to it to avoid falling through the padding.\r\n//\t//  We need entry/retw to know where to return.\r\n//1:\tentry\tsp, 16\r\n//\tretw\r\n#  else\r\n#   error \"unrecognized address register file size\"\r\n#  endif\r\n\r\n#endif /* XCHAL_HAVE_WINDOWED */\r\n\twindow_spill_common\r\n\t.endm\t// window_spill_function\r\n\r\n/*----------------------------------------------------------------------\r\n *  window_spill_common\r\n *\r\n *  Common code used by any number of invocations of the window_spill##\r\n *  and window_spill_function macros.\r\n *\r\n *  Must be instantiated exactly once within a given assembly unit,\r\n *  within call/j range of and same section as window_spill##\r\n *  macro invocations for that assembly unit.\r\n *  (Is automatically instantiated by the window_spill_function macro.)\r\n */\r\n\r\n\t.macro\twindow_spill_common\r\n#if XCHAL_HAVE_WINDOWED && (XCHAL_NUM_AREGS == 32 || XCHAL_NUM_AREGS == 64)\r\n\t.ifndef\t.L__wdwspill_defined\r\n#  if XCHAL_NUM_AREGS >= 64\r\n.L__wdwspill_assist60:\r\n\tentry\tsp, 32\r\n\tcall8\t.L__wdwspill_assist52\r\n\tretw\r\n.L__wdwspill_assist56:\r\n\tentry\tsp, 16\r\n\tcall4\t.L__wdwspill_assist52\r\n\tretw\r\n.L__wdwspill_assist52:\r\n\tentry\tsp, 48\r\n\tcall12\t.L__wdwspill_assist40\r\n\tretw\r\n.L__wdwspill_assist40:\r\n\tentry\tsp, 48\r\n\tcall12\t.L__wdwspill_assist28\r\n\tretw\r\n#  endif\r\n.L__wdwspill_assist28:\r\n\tentry\tsp, 48\r\n\tcall12\t.L__wdwspill_assist16\r\n\tretw\r\n.L__wdwspill_assist24:\r\n\tentry\tsp, 32\r\n\tcall8\t.L__wdwspill_assist16\r\n\tretw\r\n.L__wdwspill_assist20:\r\n\tentry\tsp, 16\r\n\tcall4\t.L__wdwspill_assist16\r\n\tretw\r\n.L__wdwspill_assist16:\r\n\tentry\tsp, 16\r\n\tmovi\ta15, 0\r\n\tretw\r\n\t.set\t.L__wdwspill_defined, 1\r\n\t.endif\r\n#endif /* XCHAL_HAVE_WINDOWED with 32 or 64 aregs */\r\n\t.endm\t// window_spill_common\r\n\r\n/*----------------------------------------------------------------------\r\n *  beqi32\r\n *\r\n *  macro implements version of beqi for arbitrary 32-bit immediate value\r\n *\r\n *     beqi32 ax, ay, imm32, label\r\n * \r\n *  Compares value in register ax with imm32 value and jumps to label if\r\n *  equal. Clobbers register ay if needed\r\n *\r\n */\r\n   .macro beqi32\tax, ay, imm, label\r\n    .ifeq ((\\imm-1) & ~7)\t// 1..8 ?\r\n\t\tbeqi\t\\ax, \\imm, \\label\r\n    .else\r\n      .ifeq (\\imm+1)\t\t// -1 ?\r\n\t\tbeqi\t\\ax, \\imm, \\label\r\n      .else\r\n        .ifeq (\\imm)\t\t// 0 ?\r\n\t\tbeqz\t\\ax, \\label\r\n        .else\r\n\t\t//  We could also handle immediates 10,12,16,32,64,128,256 \r\n\t\t//  but it would be a long macro...\r\n\t\tmovi\t\\ay, \\imm\r\n\t\tbeq\t\\ax, \\ay, \\label\r\n        .endif\r\n      .endif\r\n    .endif\r\n   .endm // beqi32\r\n\r\n/*----------------------------------------------------------------------\r\n *  isync_retw_nop\r\n *\r\n *  This macro must be invoked immediately after ISYNC if ISYNC\r\n *  would otherwise be immediately followed by RETW (or other instruction\r\n *  modifying WindowBase or WindowStart), in a context where\r\n *  kernel vector mode may be selected, and level-one interrupts\r\n *  and window overflows may be enabled, on an XEA1 configuration.\r\n *\r\n *  On hardware with erratum \"XEA1KWIN\" (see <xtensa/core.h> for details),\r\n *  XEA1 code must have at least one instruction between ISYNC and RETW if\r\n *  run in kernel vector mode with interrupts and window overflows enabled.\r\n */\r\n\t.macro\tisync_retw_nop\r\n#if XCHAL_MAYHAVE_ERRATUM_XEA1KWIN\r\n\tnop\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n *  abs\r\n *\r\n *  implements abs on machines that do not have it configured\r\n */\r\n\t\r\n#if !XCHAL_HAVE_ABS\r\n\t.macro abs arr, ars\r\n\t.ifc \\arr, \\ars\r\n\t//src equal dest is less efficient\r\n\tbgez \\arr, 1f\r\n\tneg \\arr, \\arr\r\n1:\t\r\n\t.else\r\n\tneg \\arr, \\ars\r\n\tmovgez \\arr, \\ars, \\ars\r\n\t.endif\r\n\t.endm\r\n#endif /* !XCHAL_HAVE_ABS */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n *  addx2\r\n *  \r\n *  implements addx2 on machines that do not have it configured\r\n *     \r\n */\r\n\r\n#if !XCHAL_HAVE_ADDX\r\n\t.macro addx2 arr, ars, art\r\n\t.ifc \\arr, \\art\r\n\t.ifc \\arr, \\ars\r\n\t// addx2 a, a, a     (not common)\r\n\t.err\r\n\t.else\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\t.endif\r\n\t.else\r\n\t//addx2 a, b, c\r\n\t//addx2 a, a, b\r\n\t//addx2 a, b, b\r\n\tslli \\arr, \\ars, 1\r\n\tadd  \\arr, \\arr, \\art\r\n\t.endif\r\n\t.endm\r\n#endif /* !XCHAL_HAVE_ADDX */\r\n\t\r\n/*----------------------------------------------------------------------\r\n *  addx4\r\n * \r\n *  implements addx4 on machines that do not have it configured\r\n *\r\n */\r\n\t\r\n#if !XCHAL_HAVE_ADDX\r\n\t.macro addx4 arr, ars, art\r\n\t.ifc \\arr, \\art\r\n\t.ifc \\arr, \\ars\r\n\t// addx4 a, a, a     (not common)\r\n\t .err\r\n\t .else\r\n\t//# addx4 a, b, a\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\t.endif\r\n\t.else\r\n\t//addx4 a, b, c\r\n\t//addx4 a, a, b\r\n\t//addx4 a, b, b\r\n\tslli \\arr, \\ars, 2\r\n\tadd  \\arr, \\arr, \\art\r\n\t.endif\r\n\t.endm\r\n#endif /* !XCHAL_HAVE_ADDX */\r\n\r\n/*----------------------------------------------------------------------\r\n *  addx8\r\n * \r\n *  implements addx8 on machines that do not have it configured\r\n * \r\n */\r\n\r\n#if !XCHAL_HAVE_ADDX\r\n\t.macro addx8 arr, ars, art\r\n\t.ifc \\arr, \\art\r\n\t.ifc \\arr, \\ars\r\n\t//addx8 a, a, a     (not common)\r\n\t.err\r\n\t.else\r\n\t//addx8 a, b, a\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\tadd \\arr, \\ars, \\art\r\n\t.endif\r\n\t.else\r\n\t//addx8 a, b, c\r\n\t//addx8 a, a, b\r\n\t//addx8 a, b, b\r\n\tslli \\arr, \\ars, 3\r\n\tadd  \\arr, \\arr, \\art\r\n\t.endif\r\n\t.endm\r\n#endif /* !XCHAL_HAVE_ADDX */\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n *  rfe_rfue\r\n * \r\n *  Maps to RFUE on XEA1, and RFE on XEA2.  No mapping on XEAX.\r\n */\r\n\r\n#if XCHAL_HAVE_XEA1\r\n\t.macro\trfe_rfue\r\n\trfue\r\n\t.endm\r\n#elif XCHAL_HAVE_XEA2\r\n\t.macro\trfe_rfue\r\n\trfe\r\n\t.endm\r\n#endif\r\n \r\n\r\n/*----------------------------------------------------------------------\r\n *  abi_entry\r\n * \r\n *  Generate proper function entry sequence for the current ABI\r\n *  (windowed or call0).  Takes care of allocating stack space (up to 1kB)\r\n *  and saving the return PC, if necessary.  The corresponding abi_return\r\n *  macro does the corresponding stack deallocation and restoring return PC.\r\n *\r\n *  Parameters are:\r\n *\r\n *\tlocsize\t\tNumber of bytes to allocate on the stack\r\n *\t\t\tfor local variables (and for args to pass to\r\n *\t\t\tcallees, if any calls are made).  Defaults to zero.\r\n *\t\t\tThe macro rounds this up to a multiple of 16.\r\n *\t\t\tNOTE:  large values are allowed (e.g. up to 1 GB).\r\n *\r\n *\tcallsize\tMaximum call size made by this function.\r\n *\t\t\tLeave zero (default) for leaf functions, i.e. if\r\n *\t\t\tthis function makes no calls to other functions.\r\n *\t\t\tOtherwise must be set to 4, 8, or 12 according\r\n *\t\t\tto whether the \"largest\" call made is a call[x]4,\r\n *\t\t\tcall[x]8, or call[x]12 (for call0 ABI, it makes\r\n *\t\t\tno difference whether this is set to 4, 8 or 12,\r\n *\t\t\tbut it must be set to one of these values).\r\n *\r\n *  NOTE:  It is up to the caller to align the entry point, declare the\r\n *  function symbol, make it global, etc.\r\n *\r\n *  NOTE:  This macro relies on assembler relaxation for large values\r\n *  of locsize.  It might not work with the no-transform directive.\r\n *  NOTE:  For the call0 ABI, this macro ensures SP is allocated or\r\n *  de-allocated cleanly, i.e. without temporarily allocating too much\r\n *  (or allocating negatively!) due to addi relaxation.\r\n *\r\n *  NOTE:  Generating the proper sequence and register allocation for\r\n *  making calls in an ABI independent manner is a separate topic not\r\n *  covered by this macro.\r\n *\r\n *  NOTE:  To access arguments, you can't use a fixed offset from SP.\r\n *  The offset depends on the ABI, whether the function is leaf, etc.\r\n *  The simplest method is probably to use the .locsz symbol, which\r\n *  is set by this macro to the actual number of bytes allocated on\r\n *  the stack, in other words, to the offset from SP to the arguments.\r\n *  E.g. for a function whose arguments are all 32-bit integers, you\r\n *  can get the 7th and 8th arguments (1st and 2nd args stored on stack)\r\n *  using:\r\n *\tl32i\ta2, sp, .locsz\r\n *\tl32i\ta3, sp, .locsz+4\r\n *  (this example works as long as locsize is under L32I's offset limit\r\n *   of 1020 minus up to 48 bytes of ABI-specific stack usage;\r\n *   otherwise you might first need to do \"addi a?, sp, .locsz\"\r\n *   or similar sequence).\r\n *\r\n *  NOTE:  For call0 ABI, this macro (and abi_return) may clobber a9\r\n *  (a caller-saved register).\r\n *\r\n *  Examples:\r\n *\t\tabi_entry\r\n *\t\tabi_entry  5\r\n *\t\tabi_entry  22, 8\r\n *\t\tabi_entry  0, 4\r\n */\r\n\r\n\t/*\r\n\t *  Compute .locsz and .callsz without emitting any instructions.\r\n\t *  Used by both abi_entry and abi_return.\r\n\t *  Assumes locsize >= 0.\r\n\t */\r\n\t.macro\tabi_entry_size locsize=0, callsize=0\r\n#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__\r\n\t.ifeq\t\\callsize\r\n\t .set\t.callsz, 16\r\n\t.else\r\n\t .ifeq\t\\callsize-4\r\n\t  .set\t.callsz, 16\r\n\t .else\r\n\t  .ifeq\t\\callsize-8\r\n\t   .set\t.callsz, 32\r\n\t  .else\r\n\t   .ifeq \\callsize-12\r\n\t    .set .callsz, 48\r\n\t   .else\r\n\t    .error\t\"abi_entry: invalid call size \\callsize\"\r\n\t   .endif\r\n\t  .endif\r\n\t .endif\r\n\t.endif\r\n\t.set\t.locsz, .callsz + ((\\locsize + 15) & -16)\r\n#else\r\n\t.set\t.callsz, \\callsize\r\n\t.if\t.callsz\t\t/* if calls, need space for return PC */\r\n\t .set\t.locsz, (\\locsize + 4 + 15) & -16\r\n\t.else\r\n\t .set\t.locsz, (\\locsize + 15) & -16\r\n\t.endif\r\n#endif\r\n\t.endm\r\n\r\n\t.macro abi_entry locsize=0, callsize=0\r\n\t.iflt\t\\locsize\r\n\t .error\t\"abi_entry: invalid negative size of locals (\\locsize)\"\r\n\t.endif\r\n\tabi_entry_size\t\\locsize, \\callsize\r\n#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__\r\n\t.ifgt\t.locsz - 32760\t/* .locsz > 32760 (ENTRY's max range)? */\r\n\t/*  Funky computation to try to have assembler use addmi efficiently if possible:  */\r\n\tentry\tsp, 0x7F00 + (.locsz & 0xF0)\r\n\taddi\ta12, sp, - ((.locsz & -0x100) - 0x7F00)\r\n\tmovsp\tsp, a12\r\n\t.else\r\n\tentry\tsp, .locsz\r\n\t.endif\r\n#else\r\n\t.if\t.locsz\r\n\t .ifle\t.locsz - 128\t/* if locsz <= 128 */\r\n\taddi\tsp, sp, -.locsz\r\n\t  .if\t.callsz\r\n\ts32i\ta0, sp, .locsz - 4\r\n\t  .endif\r\n\t .elseif  .callsz\t/* locsz > 128, with calls: */\r\n\tmovi\ta9, .locsz - 16\t\t/* note: a9 is caller-saved */\r\n\taddi\tsp, sp, -16\r\n\ts32i\ta0, sp, 12\r\n\tsub\tsp, sp, a9\r\n\t .else\t\t\t/* locsz > 128, no calls: */\r\n\tmovi\ta9, .locsz\r\n\tsub\tsp, sp, a9\r\n\t .endif\t\t\t/* end */\r\n\t.endif\r\n#endif\r\n\t.endm\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n *  abi_return\r\n * \r\n *  Generate proper function exit sequence for the current ABI\r\n *  (windowed or call0).  Takes care of freeing stack space and\r\n *  restoring the return PC, if necessary.\r\n *  NOTE:  This macro MUST be invoked following a corresponding\r\n *  abi_entry macro invocation.  For call0 ABI in particular,\r\n *  all stack and PC restoration are done according to the last\r\n *  abi_entry macro invoked before this macro in the assembly file.\r\n *\r\n *  Normally this macro takes no arguments.  However to allow\r\n *  for placing abi_return *before* abi_entry (as must be done\r\n *  for some highly optimized assembly), it optionally takes\r\n *  exactly the same arguments as abi_entry.\r\n */\r\n\r\n\t.macro abi_return\tlocsize=-1, callsize=0\r\n\t.ifge\t\\locsize\r\n\tabi_entry_size\t\\locsize, \\callsize\r\n\t.endif\r\n#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__\r\n\tretw\r\n#else\r\n\t.if\t.locsz\r\n\t .iflt\t.locsz - 128\t/* if locsz < 128 */\r\n\t  .if\t.callsz\r\n\tl32i\ta0, sp, .locsz - 4\r\n\t  .endif\r\n\taddi\tsp, sp, .locsz\r\n\t .elseif  .callsz\t/* locsz >= 128, with calls: */\r\n\taddi\ta9, sp, .locsz - 16\r\n\tl32i\ta0, a9, 12\r\n\taddi\tsp, a9, 16\r\n\t .else\t\t\t/* locsz >= 128, no calls: */\r\n\tmovi\ta9, .locsz\r\n\tadd\tsp, sp, a9\r\n\t .endif\t\t\t/* end */\r\n\t.endif\r\n\tret\r\n#endif\r\n\t.endm\r\n\r\n\r\n#endif /*XTENSA_COREASM_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/corebits.h",
    "content": "/*\r\n * xtensa/corebits.h - Xtensa Special Register field positions, masks, values.\r\n *\r\n * (In previous releases, these were defined in specreg.h, a generated file.\r\n *  This file is not generated, ie. it is processor configuration independent.)\r\n */\r\n\r\n/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/corebits.h#2 $ */\r\n\r\n/*\r\n * Copyright (c) 2005-2007 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef XTENSA_COREBITS_H\r\n#define XTENSA_COREBITS_H\r\n\r\n/*  EXCCAUSE register fields:  */\r\n#define EXCCAUSE_EXCCAUSE_SHIFT\t0\r\n#define EXCCAUSE_EXCCAUSE_MASK\t0x3F\r\n/*  EXCCAUSE register values:  */\r\n/*\r\n *  General Exception Causes\r\n *  (values of EXCCAUSE special register set by general exceptions,\r\n *   which vector to the user, kernel, or double-exception vectors).\r\n */\r\n#define EXCCAUSE_ILLEGAL\t\t0\t/* Illegal Instruction */\r\n#define EXCCAUSE_SYSCALL\t\t1\t/* System Call (SYSCALL instruction) */\r\n#define EXCCAUSE_INSTR_ERROR\t\t2\t/* Instruction Fetch Error */\r\n# define EXCCAUSE_IFETCHERROR\t\t2\t/* (backward compatibility macro, deprecated, avoid) */\r\n#define EXCCAUSE_LOAD_STORE_ERROR\t3\t/* Load Store Error */\r\n# define EXCCAUSE_LOADSTOREERROR\t3\t/* (backward compatibility macro, deprecated, avoid) */\r\n#define EXCCAUSE_LEVEL1_INTERRUPT\t4\t/* Level 1 Interrupt */\r\n# define EXCCAUSE_LEVEL1INTERRUPT\t4\t/* (backward compatibility macro, deprecated, avoid) */\r\n#define EXCCAUSE_ALLOCA\t\t\t5\t/* Stack Extension Assist (MOVSP instruction) for alloca */\r\n#define EXCCAUSE_DIVIDE_BY_ZERO\t\t6\t/* Integer Divide by Zero */\r\n#define EXCCAUSE_SPECULATION\t\t7\t/* Use of Failed Speculative Access (not implemented) */\r\n#define EXCCAUSE_PRIVILEGED\t\t8\t/* Privileged Instruction */\r\n#define EXCCAUSE_UNALIGNED\t\t9\t/* Unaligned Load or Store */\r\n/* Reserved\t\t\t\t10..11 */\r\n#define EXCCAUSE_INSTR_DATA_ERROR\t12\t/* PIF Data Error on Instruction Fetch (RB-200x and later) */\r\n#define EXCCAUSE_LOAD_STORE_DATA_ERROR\t13\t/* PIF Data Error on Load or Store (RB-200x and later) */\r\n#define EXCCAUSE_INSTR_ADDR_ERROR\t14\t/* PIF Address Error on Instruction Fetch (RB-200x and later) */\r\n#define EXCCAUSE_LOAD_STORE_ADDR_ERROR\t15\t/* PIF Address Error on Load or Store (RB-200x and later) */\r\n#define EXCCAUSE_ITLB_MISS\t\t16\t/* ITLB Miss (no ITLB entry matches, hw refill also missed) */\r\n#define EXCCAUSE_ITLB_MULTIHIT\t\t17\t/* ITLB Multihit (multiple ITLB entries match) */\r\n#define EXCCAUSE_INSTR_RING\t\t18\t/* Ring Privilege Violation on Instruction Fetch */\r\n/* Reserved\t\t\t\t19 */\t/* Size Restriction on IFetch (not implemented) */\r\n#define EXCCAUSE_INSTR_PROHIBITED\t20\t/* Cache Attribute does not allow Instruction Fetch */\r\n/* Reserved\t\t\t\t21..23 */\r\n#define EXCCAUSE_DTLB_MISS\t\t24\t/* DTLB Miss (no DTLB entry matches, hw refill also missed) */\r\n#define EXCCAUSE_DTLB_MULTIHIT\t\t25\t/* DTLB Multihit (multiple DTLB entries match) */\r\n#define EXCCAUSE_LOAD_STORE_RING\t26\t/* Ring Privilege Violation on Load or Store */\r\n/* Reserved\t\t\t\t27 */\t/* Size Restriction on Load/Store (not implemented) */\r\n#define EXCCAUSE_LOAD_PROHIBITED\t28\t/* Cache Attribute does not allow Load */\r\n#define EXCCAUSE_STORE_PROHIBITED\t29\t/* Cache Attribute does not allow Store */\r\n/* Reserved\t\t\t\t30..31 */\r\n#define EXCCAUSE_CP_DISABLED(n)\t\t(32+(n))\t/* Access to Coprocessor 'n' when disabled */\r\n#define EXCCAUSE_CP0_DISABLED\t\t32\t/* Access to Coprocessor 0 when disabled */\r\n#define EXCCAUSE_CP1_DISABLED\t\t33\t/* Access to Coprocessor 1 when disabled */\r\n#define EXCCAUSE_CP2_DISABLED\t\t34\t/* Access to Coprocessor 2 when disabled */\r\n#define EXCCAUSE_CP3_DISABLED\t\t35\t/* Access to Coprocessor 3 when disabled */\r\n#define EXCCAUSE_CP4_DISABLED\t\t36\t/* Access to Coprocessor 4 when disabled */\r\n#define EXCCAUSE_CP5_DISABLED\t\t37\t/* Access to Coprocessor 5 when disabled */\r\n#define EXCCAUSE_CP6_DISABLED\t\t38\t/* Access to Coprocessor 6 when disabled */\r\n#define EXCCAUSE_CP7_DISABLED\t\t39\t/* Access to Coprocessor 7 when disabled */\r\n/*#define EXCCAUSE_FLOATING_POINT\t40*/\t/* Floating Point Exception (not implemented) */\r\n/* Reserved\t\t\t\t40..63 */\r\n\r\n/*  PS register fields:  */\r\n#define PS_WOE_SHIFT\t\t18\r\n#define PS_WOE_MASK\t\t0x00040000\r\n#define PS_WOE\t\t\tPS_WOE_MASK\r\n#define PS_CALLINC_SHIFT\t16\r\n#define PS_CALLINC_MASK\t\t0x00030000\r\n#define PS_CALLINC(n)\t\t(((n)&3)<<PS_CALLINC_SHIFT)\t/* n = 0..3 */\r\n#define PS_OWB_SHIFT\t\t8\r\n#define PS_OWB_MASK\t\t0x00000F00\r\n#define PS_OWB(n)\t\t(((n)&15)<<PS_OWB_SHIFT)\t/* n = 0..15 (or 0..7) */\r\n#define PS_RING_SHIFT\t\t6\r\n#define PS_RING_MASK\t\t0x000000C0\r\n#define PS_RING(n)\t\t(((n)&3)<<PS_RING_SHIFT)\t/* n = 0..3 */\r\n#define PS_UM_SHIFT\t\t5\r\n#define PS_UM_MASK\t\t0x00000020\r\n#define PS_UM\t\t\tPS_UM_MASK\r\n#define PS_EXCM_SHIFT\t\t4\r\n#define PS_EXCM_MASK\t\t0x00000010\r\n#define PS_EXCM\t\t\tPS_EXCM_MASK\r\n#define PS_INTLEVEL_SHIFT\t0\r\n#define PS_INTLEVEL_MASK\t0x0000000F\r\n#define PS_INTLEVEL(n)\t\t((n)&PS_INTLEVEL_MASK)\t\t/* n = 0..15 */\r\n/*  Backward compatibility (deprecated):  */\r\n#define PS_PROGSTACK_SHIFT\tPS_UM_SHIFT\r\n#define PS_PROGSTACK_MASK\tPS_UM_MASK\r\n#define PS_PROG_SHIFT\t\tPS_UM_SHIFT\r\n#define PS_PROG_MASK\t\tPS_UM_MASK\r\n#define PS_PROG\t\t\tPS_UM\r\n\r\n/*  DBREAKCn register fields:  */\r\n#define DBREAKC_MASK_SHIFT\t\t0\r\n#define DBREAKC_MASK_MASK\t\t0x0000003F\r\n#define DBREAKC_LOADBREAK_SHIFT\t\t30\r\n#define DBREAKC_LOADBREAK_MASK\t\t0x40000000\r\n#define DBREAKC_STOREBREAK_SHIFT\t31\r\n#define DBREAKC_STOREBREAK_MASK\t\t0x80000000\r\n\r\n/*  DEBUGCAUSE register fields:  */\r\n#define DEBUGCAUSE_DEBUGINT_SHIFT\t5\r\n#define DEBUGCAUSE_DEBUGINT_MASK\t0x20\t/* debug interrupt */\r\n#define DEBUGCAUSE_BREAKN_SHIFT\t\t4\r\n#define DEBUGCAUSE_BREAKN_MASK\t\t0x10\t/* BREAK.N instruction */\r\n#define DEBUGCAUSE_BREAK_SHIFT\t\t3\r\n#define DEBUGCAUSE_BREAK_MASK\t\t0x08\t/* BREAK instruction */\r\n#define DEBUGCAUSE_DBREAK_SHIFT\t\t2\r\n#define DEBUGCAUSE_DBREAK_MASK\t\t0x04\t/* DBREAK match */\r\n#define DEBUGCAUSE_IBREAK_SHIFT\t\t1\r\n#define DEBUGCAUSE_IBREAK_MASK\t\t0x02\t/* IBREAK match */\r\n#define DEBUGCAUSE_ICOUNT_SHIFT\t\t0\r\n#define DEBUGCAUSE_ICOUNT_MASK\t\t0x01\t/* ICOUNT would increment to zero */\r\n\r\n/*  MESR register fields:  */\r\n#define MESR_MEME\t\t0x00000001\t/* memory error */\r\n#define MESR_MEME_SHIFT\t\t0\r\n#define MESR_DME\t\t0x00000002\t/* double memory error */\r\n#define MESR_DME_SHIFT\t\t1\r\n#define MESR_RCE\t\t0x00000010\t/* recorded memory error */\r\n#define MESR_RCE_SHIFT\t\t4\r\n#define MESR_LCE\t\t\r\n#define MESR_LCE_SHIFT\t\t?\r\n#define MESR_LCE_L\r\n#define MESR_ERRENAB\t\t0x00000100\r\n#define MESR_ERRENAB_SHIFT\t8\r\n#define MESR_ERRTEST\t\t0x00000200\r\n#define MESR_ERRTEST_SHIFT\t9\r\n#define MESR_DATEXC\t\t0x00000400\r\n#define MESR_DATEXC_SHIFT\t10\r\n#define MESR_INSEXC\t\t0x00000800\r\n#define MESR_INSEXC_SHIFT\t11\r\n#define MESR_WAYNUM_SHIFT\t16\r\n#define MESR_ACCTYPE_SHIFT\t20\r\n#define MESR_MEMTYPE_SHIFT\t24\r\n#define MESR_ERRTYPE_SHIFT\t30\r\n\r\n\r\n#endif /*XTENSA_COREBITS_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/hal.h",
    "content": "/*\r\n   xtensa/hal.h -- contains a definition of the Core HAL interface\r\n\r\n   All definitions in this header file are independent of any specific\r\n   Xtensa processor configuration.  Thus software (eg. OS, application,\r\n   etc) can include this header file and be compiled into configuration-\r\n   independent objects that can be distributed and eventually linked\r\n   to the HAL library (libhal.a) to create a configuration-specific\r\n   final executable.\r\n\r\n   Certain definitions, however, are release/version-specific -- such as\r\n   the XTHAL_RELEASE_xxx macros (or additions made in later versions).\r\n\r\n\r\n   $Id: //depot/rel/Boreal/Xtensa/OS/target-os-src/hal.h.tpp#3 $\r\n\r\n   Copyright (c) 1999-2010 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n*/\r\n\r\n#ifndef XTENSA_HAL_H\r\n#define XTENSA_HAL_H\r\n\r\n\r\n/****************************************************************************\r\n\t    Definitions Useful for Any Code, USER or PRIVILEGED\r\n ****************************************************************************/\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t   Constant Definitions  (shared with assembly)\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*\r\n *  Software (Xtensa Tools) version information.  Not configuration-specific!\r\n *\r\n *  NOTE:  \"release\" is a misnomer here, these are really product \"version\"\r\n *\tnumbers.  A \"release\" is a collection of product versions\r\n *\tmade available at once (together) to customers.\r\n *\tIn the past, release and version names all matched in T####.# form,\r\n *\tmaking the distinction irrelevant.  This is no longer the case.\r\n */\r\n#define XTHAL_RELEASE_MAJOR\t8000\r\n#define XTHAL_RELEASE_MINOR\t1\r\n#define XTHAL_RELEASE_NAME\t\"8.0.1\"\r\n#define XTHAL_REL_8\t1\r\n#define XTHAL_REL_8_0\t1\r\n#define XTHAL_REL_8_0_1\t1\r\n\r\n/*  HAL version numbers (these names are for backward compatibility):  */\r\n#define XTHAL_MAJOR_REV\t\tXTHAL_RELEASE_MAJOR\r\n#define XTHAL_MINOR_REV\t\tXTHAL_RELEASE_MINOR\r\n/*\r\n *  A bit of software release/version history on values of XTHAL_{MAJOR,MINOR}_REV:\r\n *\r\n *\tSW Version\tMAJOR\tMINOR\t\tComment\r\n *\t=======\t\t=====\t=====\t\t=======\r\n *\tT1015.n\t\tn/a\tn/a\t\t(HAL not yet available)\r\n *\tT1020.{0,1,2}\t0\t1\t\t(HAL beta)\r\n *\tT1020.{3,4}\t0\t2\t\tFirst release.\r\n *\tT1020.n (n>4)\t0\t2 or >3\t\t(TBD)\r\n *\tT1030.0\t\t0\t1\t\t(HAL beta)\r\n *\tT1030.{1,2}\t0\t3\t\tEquivalent to first release.\r\n *\tT1030.n (n>=3)\t0\t>= 3\t\t(TBD)\r\n *\tT1040.n\t\t1040\tn\t\tFull CHAL available from T1040.2\r\n *\tT1050.n\t\t1050\tn\t\t.\r\n *\t6.0.n\t\t6000\tn\t\tXtensa Tools v6   (RA-200x.n)\r\n *\t7.0.n\t\t7000\tn\t\tXtensa Tools v7   (RB-200x.n)\r\n *\t7.1.n\t\t7010\tn\t\tXtensa Tools v7.1 (RB-200x.(n+2))\r\n *\r\n *\r\n *  Note:  there is a distinction between the software version with\r\n *  which something is compiled (accessible using XTHAL_RELEASE_* macros)\r\n *  and the software version with which the HAL library was compiled\r\n *  (accessible using Xthal_release_* global variables).  This\r\n *  distinction is particularly relevant for vendors that distribute\r\n *  configuration-independent binaries (eg. an OS), where their customer\r\n *  might link it with a HAL of a different Xtensa software version.\r\n *  In this case, it may be appropriate for the OS to verify at run-time\r\n *  whether XTHAL_RELEASE_* and Xthal_release_* are compatible.\r\n *  [Guidelines as to which version is compatible with which are not\r\n *  currently provided explicitly, but might be inferred from reading\r\n *  OSKit documentation for all releases -- compatibility is also highly\r\n *  dependent on which HAL features are used.  Each version is usually\r\n *  backward compatible, with very few exceptions if any.]\r\n *\r\n *  Notes:\r\n *\tTornado 2.0 supported in T1020.3+, T1030.1+, and T1040.{0,1} only.\r\n *\tTornado 2.0.2 supported in T1040.2+, T1050, and 6.0.\r\n *\tCompile-time HAL port of NucleusPlus supported by T1040.2 and later.\r\n */\r\n\r\n/*  Version comparison operators (among major/minor pairs):  */\r\n#define XTHAL_REL_GE(maja,mina, majb,minb)\t((maja) > (majb) || \\\r\n\t\t\t\t\t\t ((maja) == (majb) && (mina) >= (minb)))\r\n#define XTHAL_REL_GT(maja,mina, majb,minb)\t((maja) > (majb) || \\\r\n\t\t\t\t\t\t ((maja) == (majb) && (mina) > (minb)))\r\n#define XTHAL_REL_LE(maja,mina, majb,minb)\t((maja) < (majb) || \\\r\n\t\t\t\t\t\t ((maja) == (majb) && (mina) <= (minb)))\r\n#define XTHAL_REL_LT(maja,mina, majb,minb)\t((maja) < (majb) || \\\r\n\t\t\t\t\t\t ((maja) == (majb) && (mina) < (minb)))\r\n#define XTHAL_REL_EQ(maja,mina, majb,minb)\t((maja) == (majb) && (mina) == (minb))\r\n\r\n/*  Fuzzy (3-way) logic operators:  */\r\n#define XTHAL_MAYBE\t\t-1\t/* 0=NO, 1=YES, -1=MAYBE */\r\n#define XTHAL_FUZZY_AND(a,b)\t(((a)==0 || (b)==0) ? 0 : ((a)==1 && (b)==1) ? 1 : XTHAL_MAYBE)\r\n#define XTHAL_FUZZY_OR(a,b)\t(((a)==1 || (b)==1) ? 1 : ((a)==0 && (b)==0) ? 0 : XTHAL_MAYBE)\r\n#define XTHAL_FUZZY_NOT(a)\t(((a)==0 || (a)==1) ? (1-(a)) : XTHAL_MAYBE)\r\n\r\n\r\n/*\r\n *  Architectural limit, independent of configuration:\r\n */\r\n#define XTHAL_MAX_CPS\t\t8\t/* max number of coprocessors (0..7) */\r\n\r\n/*  Misc:  */\r\n#define XTHAL_LITTLEENDIAN\t\t0\r\n#define XTHAL_BIGENDIAN\t\t\t1\r\n\r\n\r\n\r\n#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__)\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\t\tHAL\r\n  ----------------------------------------------------------------------*/\r\n\r\n/* Constant to be checked in build = (XTHAL_MAJOR_REV<<16)|XTHAL_MINOR_REV */\r\nextern const unsigned int Xthal_rev_no;\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tOptional/Custom Processor State\r\n  ----------------------------------------------------------------------*/\r\n\r\n/* save & restore the extra processor state */\r\nextern void xthal_save_extra(void *base);\r\nextern void xthal_restore_extra(void *base);\r\n\r\nextern void xthal_save_cpregs(void *base, int);\r\nextern void xthal_restore_cpregs(void *base, int);\r\n/* versions specific to each coprocessor id */\r\nextern void xthal_save_cp0(void *base);\r\nextern void xthal_save_cp1(void *base);\r\nextern void xthal_save_cp2(void *base);\r\nextern void xthal_save_cp3(void *base);\r\nextern void xthal_save_cp4(void *base);\r\nextern void xthal_save_cp5(void *base);\r\nextern void xthal_save_cp6(void *base);\r\nextern void xthal_save_cp7(void *base);\r\nextern void xthal_restore_cp0(void *base);\r\nextern void xthal_restore_cp1(void *base);\r\nextern void xthal_restore_cp2(void *base);\r\nextern void xthal_restore_cp3(void *base);\r\nextern void xthal_restore_cp4(void *base);\r\nextern void xthal_restore_cp5(void *base);\r\nextern void xthal_restore_cp6(void *base);\r\nextern void xthal_restore_cp7(void *base);\r\n/* pointers to each of the functions above */\r\nextern void* Xthal_cpregs_save_fn[XTHAL_MAX_CPS];\r\nextern void* Xthal_cpregs_restore_fn[XTHAL_MAX_CPS];\r\n/* similarly for non-windowed ABI (may be same or different) */\r\nextern void* Xthal_cpregs_save_nw_fn[XTHAL_MAX_CPS];\r\nextern void* Xthal_cpregs_restore_nw_fn[XTHAL_MAX_CPS];\r\n\r\n/*extern void xthal_save_all_extra(void *base);*/\r\n/*extern void xthal_restore_all_extra(void *base);*/\r\n\r\n/* space for processor state */\r\nextern const unsigned int Xthal_extra_size;\r\nextern const unsigned int Xthal_extra_align;\r\nextern const unsigned int Xthal_cpregs_size[XTHAL_MAX_CPS];\r\nextern const unsigned int Xthal_cpregs_align[XTHAL_MAX_CPS];\r\nextern const unsigned int Xthal_all_extra_size;\r\nextern const unsigned int Xthal_all_extra_align;\r\n/* coprocessor names */\r\nextern const char * const Xthal_cp_names[XTHAL_MAX_CPS];\r\n\r\n/* initialize the extra processor */\r\n/*extern void xthal_init_extra(void);*/\r\n/* initialize the TIE coprocessor */\r\n/*extern void xthal_init_cp(int);*/\r\n\r\n/* initialize the extra processor */\r\nextern void xthal_init_mem_extra(void *);\r\n/* initialize the TIE coprocessor */\r\nextern void xthal_init_mem_cp(void *, int);\r\n\r\n/* the number of TIE coprocessors contiguous from zero (for Tor2) */\r\nextern const unsigned int Xthal_num_coprocessors;\r\n\r\n/* actual number of coprocessors */\r\nextern const unsigned char Xthal_cp_num;\r\n/* index of highest numbered coprocessor, plus one */\r\nextern const unsigned char Xthal_cp_max;\r\n/* index of highest allowed coprocessor number, per cfg, plus one */\r\n/*extern const unsigned char Xthal_cp_maxcfg;*/\r\n/* bitmask of which coprocessors are present */\r\nextern const unsigned int  Xthal_cp_mask;\r\n\r\n/* read & write extra state register */\r\n/*extern int xthal_read_extra(void *base, unsigned reg, unsigned *value);*/\r\n/*extern int xthal_write_extra(void *base, unsigned reg, unsigned value);*/\r\n\r\n/* read & write a TIE coprocessor register */\r\n/*extern int xthal_read_cpreg(void *base, int cp, unsigned reg, unsigned *value);*/\r\n/*extern int xthal_write_cpreg(void *base, int cp, unsigned reg, unsigned value);*/\r\n\r\n/* return coprocessor number based on register */\r\n/*extern int xthal_which_cp(unsigned reg);*/\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tRegister Windows\r\n  ----------------------------------------------------------------------*/\r\n\r\n/* number of registers in register window */\r\nextern const unsigned int  Xthal_num_aregs;\r\nextern const unsigned char Xthal_num_aregs_log2;\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tCache\r\n  ----------------------------------------------------------------------*/\r\n\r\n/* size of the cache lines in log2(bytes) */\r\nextern const unsigned char Xthal_icache_linewidth;\r\nextern const unsigned char Xthal_dcache_linewidth;\r\n/* size of the cache lines in bytes (2^linewidth) */\r\nextern const unsigned short Xthal_icache_linesize;\r\nextern const unsigned short Xthal_dcache_linesize;\r\n\r\n/* size of the caches in bytes (ways * 2^(linewidth + setwidth)) */\r\nextern const unsigned int  Xthal_icache_size;\r\nextern const unsigned int  Xthal_dcache_size;\r\n/* cache features */\r\nextern const unsigned char Xthal_dcache_is_writeback;\r\n\r\n/* invalidate the caches */\r\nextern void xthal_icache_region_invalidate( void *addr, unsigned size );\r\nextern void xthal_dcache_region_invalidate( void *addr, unsigned size );\r\nextern void xthal_icache_line_invalidate(void *addr);\r\nextern void xthal_dcache_line_invalidate(void *addr);\r\n/* write dirty data back */\r\nextern void xthal_dcache_region_writeback( void *addr, unsigned size );\r\nextern void xthal_dcache_line_writeback(void *addr);\r\n/* write dirty data back and invalidate */\r\nextern void xthal_dcache_region_writeback_inv( void *addr, unsigned size );\r\nextern void xthal_dcache_line_writeback_inv(void *addr);\r\n\r\n/* sync icache and memory */\r\nextern void xthal_icache_sync( void );\r\n/* sync dcache and memory */\r\nextern void xthal_dcache_sync( void );\r\n\r\n/* coherency (low-level -- not normally called directly) */\r\nextern void xthal_cache_coherence_on( void );\r\nextern void xthal_cache_coherence_off( void );\r\n/* coherency (high-level) */\r\nextern void xthal_cache_coherence_optin( void );\r\nextern void xthal_cache_coherence_optout( void );\r\n\r\n/* prefetch */\r\n#define XTHAL_PREFETCH_ENABLE\t-1\r\n#define XTHAL_PREFETCH_DISABLE\t0\r\nextern int  xthal_set_cache_prefetch( int );\r\nextern int  xthal_get_cache_prefetch( void );\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tDebug\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  1 if debug option configured, 0 if not:  */\r\nextern const int Xthal_debug_configured;\r\n\r\n/*  Set (plant) and remove software breakpoint, both synchronizing cache:  */\r\nextern unsigned int xthal_set_soft_break(void *addr);\r\nextern void         xthal_remove_soft_break(void *addr, unsigned int);\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tDisassembler\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  Max expected size of the return buffer for a disassembled instruction (hint only):  */\r\n#define XTHAL_DISASM_BUFSIZE\t80\r\n\r\n/*  Disassembly option bits for selecting what to return:  */\r\n#define XTHAL_DISASM_OPT_ADDR\t0x0001\t/* display address */\r\n#define XTHAL_DISASM_OPT_OPHEX\t0x0002\t/* display opcode bytes in hex */\r\n#define XTHAL_DISASM_OPT_OPCODE\t0x0004\t/* display opcode name (mnemonic) */\r\n#define XTHAL_DISASM_OPT_PARMS\t0x0008\t/* display parameters */\r\n#define XTHAL_DISASM_OPT_ALL\t0x0FFF\t/* display everything */\r\n\r\n/* routine to get a string for the disassembled instruction */\r\nextern int xthal_disassemble( unsigned char *instr_buf, void *tgt_addr,\r\n\t\t       char *buffer, unsigned buflen, unsigned options );\r\n\r\n/* routine to get the size of the next instruction. Returns 0 for\r\n   illegal instruction */\r\nextern int xthal_disassemble_size( unsigned char *instr_buf );\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tInstruction/Data RAM/ROM Access\r\n  ----------------------------------------------------------------------*/\r\n\r\nextern void* xthal_memcpy(void *dst, const void *src, unsigned len);\r\nextern void* xthal_bcopy(const void *src, void *dst, unsigned len);\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n                           MP Synchronization\r\n  ----------------------------------------------------------------------*/\r\n\r\nextern int      xthal_compare_and_set( int *addr, int test_val, int compare_val );\r\n\r\n/*extern const char  Xthal_have_s32c1i;*/\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n                             Miscellaneous\r\n  ----------------------------------------------------------------------*/\r\n\r\nextern const unsigned int  Xthal_release_major;\r\nextern const unsigned int  Xthal_release_minor;\r\nextern const char * const  Xthal_release_name;\r\nextern const char * const  Xthal_release_internal;\r\n\r\nextern const unsigned char Xthal_memory_order;\r\nextern const unsigned char Xthal_have_windowed;\r\nextern const unsigned char Xthal_have_density;\r\nextern const unsigned char Xthal_have_booleans;\r\nextern const unsigned char Xthal_have_loops;\r\nextern const unsigned char Xthal_have_nsa;\r\nextern const unsigned char Xthal_have_minmax;\r\nextern const unsigned char Xthal_have_sext;\r\nextern const unsigned char Xthal_have_clamps;\r\nextern const unsigned char Xthal_have_mac16;\r\nextern const unsigned char Xthal_have_mul16;\r\nextern const unsigned char Xthal_have_fp;\r\nextern const unsigned char Xthal_have_speculation;\r\nextern const unsigned char Xthal_have_threadptr;\r\n\r\nextern const unsigned char Xthal_have_pif;\r\nextern const unsigned short Xthal_num_writebuffer_entries;\r\n\r\nextern const unsigned int  Xthal_build_unique_id;\r\n/*  Version info for hardware targeted by software upgrades:  */\r\nextern const unsigned int  Xthal_hw_configid0;\r\nextern const unsigned int  Xthal_hw_configid1;\r\nextern const unsigned int  Xthal_hw_release_major;\r\nextern const unsigned int  Xthal_hw_release_minor;\r\nextern const char * const  Xthal_hw_release_name;\r\nextern const char * const  Xthal_hw_release_internal;\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */\r\n\r\n\r\n\r\n\r\n\r\n/****************************************************************************\r\n    Definitions Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code\r\n ****************************************************************************/\r\n\r\n\r\n#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY\r\n\r\n/*----------------------------------------------------------------------\r\n\t   Constant Definitions  (shared with assembly)\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*\r\n *  Architectural limits, independent of configuration.\r\n *  Note that these are ISA-defined limits, not micro-architecture implementation\r\n *  limits enforced by the Xtensa Processor Generator (which may be stricter than\r\n *  these below).\r\n */\r\n#define XTHAL_MAX_INTERRUPTS\t32\t/* max number of interrupts (0..31) */\r\n#define XTHAL_MAX_INTLEVELS\t16\t/* max number of interrupt levels (0..15) */\r\n\t\t\t\t\t/* (as of T1040, implementation limit is 7: 0..6) */\r\n#define XTHAL_MAX_TIMERS\t4\t/* max number of timers (CCOMPARE0..CCOMPARE3) */\r\n\t\t\t\t\t/* (as of T1040, implementation limit is 3: 0..2) */\r\n\r\n/*  Interrupt types:  */\r\n#define XTHAL_INTTYPE_UNCONFIGURED\t0\r\n#define XTHAL_INTTYPE_SOFTWARE\t\t1\r\n#define XTHAL_INTTYPE_EXTERN_EDGE\t2\r\n#define XTHAL_INTTYPE_EXTERN_LEVEL\t3\r\n#define XTHAL_INTTYPE_TIMER\t\t4\r\n#define XTHAL_INTTYPE_NMI\t\t5\r\n#define XTHAL_INTTYPE_WRITE_ERROR\t6\r\n#define XTHAL_MAX_INTTYPES\t\t7\t/* number of interrupt types */\r\n\r\n/*  Timer related:  */\r\n#define XTHAL_TIMER_UNCONFIGURED\t-1\t/* Xthal_timer_interrupt[] value for non-existent timers */\r\n#define XTHAL_TIMER_UNASSIGNED\tXTHAL_TIMER_UNCONFIGURED\t/* (for backwards compatibility only) */\r\n\r\n/*  Local Memory ECC/Parity:  */\r\n#define XTHAL_MEMEP_PARITY\t1\r\n#define XTHAL_MEMEP_ECC\t\t2\r\n/*  Flags parameter to xthal_memep_inject_error():  */\r\n#define XTHAL_MEMEP_F_LOCAL\t\t0\t/* local memory (default) */\r\n#define XTHAL_MEMEP_F_DCACHE_DATA\t4\t/* data cache data */\r\n#define XTHAL_MEMEP_F_DCACHE_TAG\t5\t/* data cache tag */\r\n#define XTHAL_MEMEP_F_ICACHE_DATA\t6\t/* instruction cache data */\r\n#define XTHAL_MEMEP_F_ICACHE_TAG\t7\t/* instruction cache tag */\r\n#define XTHAL_MEMEP_F_CORRECTABLE\t16\t/* inject correctable error\r\n\t\t\t\t\t\t   (default is non-corr.) */\r\n\r\n\r\n/*  Access Mode bits (tentative):  */\t/* bit abbr unit short_name       PPC equ - Description */\r\n#define XTHAL_AMB_EXCEPTION\t0\t/* 001 E EX fls: EXception        none\r\n\t\t\t\t\t   exception on any access (aka \"illegal\") */\r\n#define XTHAL_AMB_HITCACHE\t1\t/* 002 C CH fls: use Cache on Hit ~(I CI)\r\n\t\t\t\t\t   [or H HC]  way from tag match;\r\n\t\t\t\t\t   [or U UC] (ISA: same except Isolate case) */\r\n#define XTHAL_AMB_ALLOCATE\t2\t/* 004 A AL fl?: ALlocate         none\r\n\t\t\t\t\t   [or F FI fill] refill cache on miss, way from LRU\r\n\t\t\t\t\t   (ISA: Read/Write Miss Refill) */\r\n#define XTHAL_AMB_WRITETHRU\t3\t/* 008 W WT --s: WriteThrough     W WT\r\n\t\t\t\t\t   store immediately to memory (ISA: same) */\r\n#define XTHAL_AMB_ISOLATE\t4\t/* 010 I IS fls: ISolate          none\r\n\t\t\t\t\t   use cache regardless of hit-vs-miss,\r\n\t\t\t\t\t   way from vaddr (ISA: use-cache-on-miss+hit) */\r\n#define XTHAL_AMB_GUARD\t\t5\t/* 020 G GU ?l?: GUard            G *\r\n\t\t\t\t\t   non-speculative; spec/replay refs not permitted */\r\n#define XTHAL_AMB_COHERENT\t6\t/* 040 M MC ?ls: Mem/MP Coherent  M\r\n\t\t\t\t\t   on read, other CPU/bus-master may need to supply data;\r\n\t\t\t\t\t   on write, maybe redirect to or flush other CPU dirty line; etc */\r\n#if 0\r\n#define XTHAL_AMB_ORDERED\tx\t/* 000 O OR fls: ORdered          G *\r\n\t\t\t\t\t   mem accesses cannot be out of order */\r\n#define XTHAL_AMB_FUSEWRITES\tx\t/* 000 F FW --s: FuseWrites       none\r\n\t\t\t\t\t   allow combining/merging/coalescing multiple writes\r\n\t\t\t\t\t   (to same datapath data unit) into one\r\n\t\t\t\t\t   (implied by writeback) */\r\n#define XTHAL_AMB_TRUSTED\tx\t/* 000 T TR ?l?: TRusted          none\r\n\t\t\t\t\t   memory will not bus error (if it does,\r\n\t\t\t\t\t   handle as fatal imprecise interrupt) */\r\n#define XTHAL_AMB_PREFETCH\tx\t/* 000 P PR fl?: PRefetch         none\r\n\t\t\t\t\t   on refill, read line+1 into prefetch buffers */\r\n#define XTHAL_AMB_STREAM\tx\t/* 000 S ST ???: STreaming        none\r\n\t\t\t\t\t   access one of N stream buffers */\r\n#endif /*0*/\r\n\r\n#define XTHAL_AM_EXCEPTION\t(1<<XTHAL_AMB_EXCEPTION)\r\n#define XTHAL_AM_HITCACHE\t(1<<XTHAL_AMB_HITCACHE)\r\n#define XTHAL_AM_ALLOCATE\t(1<<XTHAL_AMB_ALLOCATE)\r\n#define XTHAL_AM_WRITETHRU\t(1<<XTHAL_AMB_WRITETHRU)\r\n#define XTHAL_AM_ISOLATE\t(1<<XTHAL_AMB_ISOLATE)\r\n#define XTHAL_AM_GUARD\t\t(1<<XTHAL_AMB_GUARD)\r\n#define XTHAL_AM_COHERENT\t(1<<XTHAL_AMB_COHERENT)\r\n#if 0\r\n#define XTHAL_AM_ORDERED\t(1<<XTHAL_AMB_ORDERED)\r\n#define XTHAL_AM_FUSEWRITES\t(1<<XTHAL_AMB_FUSEWRITES)\r\n#define XTHAL_AM_TRUSTED\t(1<<XTHAL_AMB_TRUSTED)\r\n#define XTHAL_AM_PREFETCH\t(1<<XTHAL_AMB_PREFETCH)\r\n#define XTHAL_AM_STREAM\t\t(1<<XTHAL_AMB_STREAM)\r\n#endif /*0*/\r\n\r\n/*\r\n *  Allowed Access Modes (bit combinations).\r\n *\r\n *  Columns are:\r\n *  \"FOGIWACE\"\r\n *\tAccess mode bits (see XTHAL_AMB_xxx above).\r\n *\t<letter> = bit is set\r\n *\t'-'      = bit is clear\r\n *\t'.'      = bit is irrelevant / don't care, as follows:\r\n *\t\t\tE=1 makes all others irrelevant\r\n *\t\t\tW,F relevant only for stores\r\n *  \"2345\"\r\n *\tIndicates which Xtensa releases support the corresponding\r\n *\taccess mode.  Releases for each character column are:\r\n *\t\t2 = prior to T1020.2:   T1015 (V1.5), T1020.0, T1020.1\r\n *\t\t3 = T1020.2 and later:  T1020.2+, T1030\r\n *\t\t4 = T1040\r\n *\t\t5 = T1050 (maybe), LX1, LX2, LX2.1\r\n *\t\t7 = LX2.2\r\n *\t\t8 = LX3.0\r\n *\tAnd the character column contents are:\r\n *\t\t<number> = supported by release(s)\r\n *\t\t\".\" = unsupported by release(s)\r\n *\t\t\"?\" = support unknown\r\n */\r\n\t\t\t\t\t\t/* FOMGIWACE 234578 */\r\n/*  For instruction fetch:  */\r\n#define XTHAL_FAM_EXCEPTION\t\t0x001\t/* ........E 234578 exception */\r\n/*efine XTHAL_FAM_ISOLATE*/\t      /*0x012*/\t/* .---I.-C- ...... isolate */\r\n#define XTHAL_FAM_BYPASS\t\t0x000\t/* .----.--- 234578 bypass */\r\n/*efine XTHAL_FAM_NACACHED*/\t      /*0x002*/\t/* .----.-C- ...... cached no-allocate (frozen) */\r\n#define XTHAL_FAM_CACHED\t\t0x006\t/* .----.AC- 234578 cached */\r\n/*  For data load:  */\r\n#define XTHAL_LAM_EXCEPTION\t\t0x001\t/* ........E 234578 exception */\r\n#define XTHAL_LAM_ISOLATE\t\t0x012\t/* .---I.-C- 234578 isolate */\r\n#define XTHAL_LAM_BYPASS\t\t0x000\t/* .O---.--- 2..... bypass speculative */\r\n#define XTHAL_LAM_BYPASSG\t\t0x020\t/* .O-G-.--- .34578 bypass guarded */\r\n#define XTHAL_LAM_CACHED_NOALLOC\t0x002\t/* .O---.-C- 234578 cached no-allocate speculative */\r\n#define XTHAL_LAM_NACACHED\t\tXTHAL_LAM_CACHED_NOALLOC\r\n#define XTHAL_LAM_NACACHEDG\t\t0x022\t/* .O-G-.-C- .?.... cached no-allocate guarded */\r\n#define XTHAL_LAM_CACHED\t\t0x006\t/* .----.AC- 234578 cached speculative */\r\n#define XTHAL_LAM_COHCACHED\t\t0x046\t/* .-M--.AC- ....*8 cached speculative MP-coherent */\r\n/*  For data store:  */\r\n#define XTHAL_SAM_EXCEPTION\t\t0x001\t/* ........E 234578 exception */\r\n#define XTHAL_SAM_ISOLATE\t\t0x032\t/* .--GI--C- 234578 isolate */\r\n#define XTHAL_SAM_BYPASS\t\t0x028\t/* -O-G-W--- 234578 bypass */\r\n#define XTHAL_SAM_WRITETHRU\t\t0x02A\t/* -O-G-W-C- 234578 writethrough */\r\n/*efine XTHAL_SAM_WRITETHRU_ALLOC*/   /*0x02E*/\t/* -O-G-WAC- ...... writethrough allocate */\r\n#define XTHAL_SAM_WRITEBACK\t\t0x026\t/* F-MG--AC- ...578 writeback */\r\n#define XTHAL_SAM_COHWRITEBACK\t\t0x066\t/* F-MG--AC- ....*8 writeback MP-coherent */\r\n#define XTHAL_SAM_WRITEBACK_NOALLOC\t0x022\t/* ?--G---C- .....8 writeback no-allocate */\r\n\r\n#if 0\r\n/*\r\n    Cache attribute encoding for CACHEATTR (per ISA):\r\n    (Note:  if this differs from ISA Ref Manual, ISA has precedence)\r\n\r\n\tInst-fetches\tLoads\t\tStores\r\n\t-------------\t------------\t-------------\r\n0x0\tFCA_EXCEPTION\tLCA_NACACHED\tSCA_WRITETHRU\tcached no-allocate (previously misnamed \"uncached\")\r\n0x1\tFCA_CACHED\tLCA_CACHED\tSCA_WRITETHRU\tcached\r\n0x2\tFCA_BYPASS\tLCA_BYPASS_G*\tSCA_BYPASS\tbypass cache (what most people call uncached)\r\n0x3\tFCA_CACHED\tLCA_CACHED\tSCA_WRITEALLOCF\twrite-allocate\r\n\t\t     or LCA_EXCEPTION\tSCA_EXCEPTION\t(if unimplemented)\r\n0x4\tFCA_CACHED\tLCA_CACHED\tSCA_WRITEBACK[M] write-back [MP-coherent]\r\n\t\t     or LCA_EXCEPTION\tSCA_EXCEPTION\t(if unimplemented)\r\n0x5\tFCA_CACHED\tLCA_CACHED\tSCA_WRITEBACK_NOALLOC\twrite-back no-allocate\r\n     or\tFCA_EXCEPTION\tLCA_EXCEPTION\tSCA_EXCEPTION\t(if unimplemented)\r\n0x6..D\tFCA_EXCEPTION\tLCA_EXCEPTION\tSCA_EXCEPTION\t(reserved)\r\n0xE\tFCA_EXCEPTION\tLCA_ISOLATE\tSCA_ISOLATE\tisolate\r\n0xF\tFCA_EXCEPTION\tLCA_EXCEPTION\tSCA_EXCEPTION\tillegal\r\n     *  Prior to T1020.2?, guard feature not supported, this defaulted to speculative (no _G)\r\n*/\r\n#endif /*0*/\r\n\r\n\r\n#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__)\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tRegister Windows\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  This spill any live register windows (other than the caller's):\r\n *  (NOTE:  current implementation require privileged code, but\r\n *   a user-callable implementation is possible.)  */\r\nextern void      xthal_window_spill( void );\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tOptional/Custom Processor State\r\n  ----------------------------------------------------------------------*/\r\n\r\n/* validate & invalidate the TIE register file */\r\nextern void xthal_validate_cp(int);\r\nextern void xthal_invalidate_cp(int);\r\n\r\n/* read and write cpenable register */\r\nextern void xthal_set_cpenable(unsigned);\r\nextern unsigned xthal_get_cpenable(void);\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tInterrupts\r\n  ----------------------------------------------------------------------*/\r\n\r\n/* the number of interrupt levels */\r\nextern const unsigned char Xthal_num_intlevels;\r\n/* the number of interrupts */\r\nextern const unsigned char Xthal_num_interrupts;\r\n\r\n/* mask for level of interrupts */\r\nextern const unsigned int Xthal_intlevel_mask[XTHAL_MAX_INTLEVELS];\r\n/* mask for level 0 to N interrupts */\r\nextern const unsigned int Xthal_intlevel_andbelow_mask[XTHAL_MAX_INTLEVELS];\r\n\r\n/* level of each interrupt */\r\nextern const unsigned char Xthal_intlevel[XTHAL_MAX_INTERRUPTS];\r\n\r\n/* type per interrupt */\r\nextern const unsigned char Xthal_inttype[XTHAL_MAX_INTERRUPTS];\r\n\r\n/* masks of each type of interrupt */\r\nextern const unsigned int Xthal_inttype_mask[XTHAL_MAX_INTTYPES];\r\n\r\n/* interrupt numbers assigned to each timer interrupt */\r\nextern const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS];\r\n\r\n/*  INTENABLE,INTERRUPT,INTSET,INTCLEAR register access functions:  */\r\nextern unsigned  xthal_get_intenable( void );\r\nextern void      xthal_set_intenable( unsigned );\r\nextern unsigned  xthal_get_interrupt( void );\r\n#define xthal_get_intread\txthal_get_interrupt\t/* backward compatibility */\r\nextern void      xthal_set_intset( unsigned );\r\nextern void      xthal_set_intclear( unsigned );\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tDebug\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  Number of instruction and data break registers:  */\r\nextern const int Xthal_num_ibreak;\r\nextern const int Xthal_num_dbreak;\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tCore Counter\r\n  ----------------------------------------------------------------------*/\r\n\r\n/* counter info */\r\nextern const unsigned char Xthal_have_ccount;\t/* set if CCOUNT register present */\r\nextern const unsigned char Xthal_num_ccompare;\t/* number of CCOMPAREn registers */\r\n\r\n/* get CCOUNT register (if not present return 0) */\r\nextern unsigned xthal_get_ccount(void);\r\n\r\n/* set and get CCOMPAREn registers (if not present, get returns 0) */\r\nextern void     xthal_set_ccompare(int, unsigned);\r\nextern unsigned xthal_get_ccompare(int);\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n                             Miscellaneous\r\n  ----------------------------------------------------------------------*/\r\n\r\nextern const unsigned char Xthal_have_prid;\r\nextern const unsigned char Xthal_have_exceptions;\r\nextern const unsigned char Xthal_xea_version;\r\nextern const unsigned char Xthal_have_interrupts;\r\nextern const unsigned char Xthal_have_highlevel_interrupts;\r\nextern const unsigned char Xthal_have_nmi;\r\n\r\nextern unsigned xthal_get_prid( void );\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\tVirtual interrupt prioritization (DEPRECATED)\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  Convert between interrupt levels (as per PS.INTLEVEL) and virtual interrupt priorities:  */\r\nextern unsigned\txthal_vpri_to_intlevel(unsigned vpri);\r\nextern unsigned\txthal_intlevel_to_vpri(unsigned intlevel);\r\n\r\n/*  Enables/disables given set (mask) of interrupts; returns previous enabled-mask of all ints:  */\r\nextern unsigned\txthal_int_enable(unsigned);\r\nextern unsigned\txthal_int_disable(unsigned);\r\n\r\n/*  Set/get virtual priority of an interrupt:  */\r\nextern int\txthal_set_int_vpri(int intnum, int vpri);\r\nextern int\txthal_get_int_vpri(int intnum);\r\n\r\n/*  Set/get interrupt lockout level for exclusive access to virtual priority data structures:  */\r\nextern void\txthal_set_vpri_locklevel(unsigned intlevel);\r\nextern unsigned\txthal_get_vpri_locklevel(void);\r\n\r\n/*  Set/get current virtual interrupt priority:  */\r\nextern unsigned\txthal_set_vpri(unsigned vpri);\r\nextern unsigned\txthal_get_vpri(void);\r\nextern unsigned\txthal_set_vpri_intlevel(unsigned intlevel);\r\nextern unsigned\txthal_set_vpri_lock(void);\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\tGeneric Interrupt Trampolining Support (DEPRECATED)\r\n  ----------------------------------------------------------------------*/\r\n\r\ntypedef void (XtHalVoidFunc)(void);\r\n\r\n/*  Bitmask of interrupts currently trampolining down:  */\r\nextern unsigned Xthal_tram_pending;\r\n\r\n/*\r\n *  Bitmask of which interrupts currently trampolining down synchronously are\r\n *  actually enabled; this bitmask is necessary because INTENABLE cannot hold\r\n *  that state (sync-trampolining interrupts must be kept disabled while\r\n *  trampolining);  in the current implementation, any bit set here is not set\r\n *  in INTENABLE, and vice-versa; once a sync-trampoline is handled (at level\r\n *  one), its enable bit must be moved from here to INTENABLE:\r\n */\r\nextern unsigned Xthal_tram_enabled;\r\n\r\n/*  Bitmask of interrupts configured for sync trampolining:  */\r\nextern unsigned Xthal_tram_sync;\r\n\r\n/*  Trampoline support functions:  */\r\nextern unsigned  xthal_tram_pending_to_service( void );\r\nextern void      xthal_tram_done( unsigned serviced_mask );\r\nextern int       xthal_tram_set_sync( int intnum, int sync );\r\nextern XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn );\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n\t\t\tInternal Memories\r\n  ----------------------------------------------------------------------*/\r\n\r\nextern const unsigned char Xthal_num_instrom;\r\nextern const unsigned char Xthal_num_instram;\r\nextern const unsigned char Xthal_num_datarom;\r\nextern const unsigned char Xthal_num_dataram;\r\nextern const unsigned char Xthal_num_xlmi;\r\n\r\n/*  Each of the following arrays contains at least one entry,\r\n *  or as many entries as needed if more than one:  */\r\nextern const unsigned int  Xthal_instrom_vaddr[];\r\nextern const unsigned int  Xthal_instrom_paddr[];\r\nextern const unsigned int  Xthal_instrom_size [];\r\nextern const unsigned int  Xthal_instram_vaddr[];\r\nextern const unsigned int  Xthal_instram_paddr[];\r\nextern const unsigned int  Xthal_instram_size [];\r\nextern const unsigned int  Xthal_datarom_vaddr[];\r\nextern const unsigned int  Xthal_datarom_paddr[];\r\nextern const unsigned int  Xthal_datarom_size [];\r\nextern const unsigned int  Xthal_dataram_vaddr[];\r\nextern const unsigned int  Xthal_dataram_paddr[];\r\nextern const unsigned int  Xthal_dataram_size [];\r\nextern const unsigned int  Xthal_xlmi_vaddr[];\r\nextern const unsigned int  Xthal_xlmi_paddr[];\r\nextern const unsigned int  Xthal_xlmi_size [];\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n   \t\t\t\tCache\r\n  ----------------------------------------------------------------------*/\r\n\r\n/* number of cache sets in log2(lines per way) */\r\nextern const unsigned char Xthal_icache_setwidth;\r\nextern const unsigned char Xthal_dcache_setwidth;\r\n/* cache set associativity (number of ways) */\r\nextern const unsigned int  Xthal_icache_ways;\r\nextern const unsigned int  Xthal_dcache_ways;\r\n/* cache features */\r\nextern const unsigned char Xthal_icache_line_lockable;\r\nextern const unsigned char Xthal_dcache_line_lockable;\r\n\r\n/* cache attribute register control (used by other HAL routines) */\r\nextern unsigned xthal_get_cacheattr( void );\r\nextern unsigned xthal_get_icacheattr( void );\r\nextern unsigned xthal_get_dcacheattr( void );\r\nextern void     xthal_set_cacheattr( unsigned );\r\nextern void     xthal_set_icacheattr( unsigned );\r\nextern void     xthal_set_dcacheattr( unsigned );\r\n/* set cache attribute (access modes) for a range of memory */\r\nextern int      xthal_set_region_attribute( void *addr, unsigned size,\r\n\t\t\t\t\t    unsigned cattr, unsigned flags );\r\n/*  Bits of flags parameter to xthal_set_region_attribute():  */\r\n#define XTHAL_CAFLAG_EXPAND\t\t0x000100\t/* only expand allowed access to range, don't reduce it */\r\n#define XTHAL_CAFLAG_EXACT\t\t0x000200\t/* return error if can't apply change to exact range specified */\r\n#define XTHAL_CAFLAG_NO_PARTIAL\t\t0x000400\t/* don't apply change to regions partially covered by range */\r\n#define XTHAL_CAFLAG_NO_AUTO_WB\t\t0x000800\t/* don't writeback data after leaving writeback attribute */\r\n#define XTHAL_CAFLAG_NO_AUTO_INV\t0x001000\t/* don't invalidate after disabling cache (entering bypass) */\r\n\r\n/* enable caches */\r\nextern void xthal_icache_enable( void );\t/* DEPRECATED */\r\nextern void xthal_dcache_enable( void );\t/* DEPRECATED */\r\n/* disable caches */\r\nextern void xthal_icache_disable( void );\t/* DEPRECATED */\r\nextern void xthal_dcache_disable( void );\t/* DEPRECATED */\r\n\r\n/* invalidate the caches */\r\nextern void xthal_icache_all_invalidate( void );\r\nextern void xthal_dcache_all_invalidate( void );\r\n/* write dirty data back */\r\nextern void xthal_dcache_all_writeback( void );\r\n/* write dirty data back and invalidate */\r\nextern void xthal_dcache_all_writeback_inv( void );\r\n/* prefetch and lock specified memory range into cache */\r\nextern void xthal_icache_region_lock( void *addr, unsigned size );\r\nextern void xthal_dcache_region_lock( void *addr, unsigned size );\r\nextern void xthal_icache_line_lock(void *addr);\r\nextern void xthal_dcache_line_lock(void *addr);\r\n/* unlock from cache */\r\nextern void xthal_icache_all_unlock( void );\r\nextern void xthal_dcache_all_unlock( void );\r\nextern void xthal_icache_region_unlock( void *addr, unsigned size );\r\nextern void xthal_dcache_region_unlock( void *addr, unsigned size );\r\nextern void xthal_icache_line_unlock(void *addr);\r\nextern void xthal_dcache_line_unlock(void *addr);\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n                         Local Memory ECC/Parity\r\n  ----------------------------------------------------------------------*/\r\n\r\n/*  Inject memory errors; flags is bit combination of XTHAL_MEMEP_F_xxx:  */\r\nextern void xthal_memep_inject_error(void *addr, int size, int flags);\r\n\r\n\r\n\r\n/*----------------------------------------------------------------------\r\n                         Memory Management Unit\r\n  ----------------------------------------------------------------------*/\r\n\r\nextern const unsigned char Xthal_have_spanning_way;\r\nextern const unsigned char Xthal_have_identity_map;\r\nextern const unsigned char Xthal_have_mimic_cacheattr;\r\nextern const unsigned char Xthal_have_xlt_cacheattr;\r\nextern const unsigned char Xthal_have_cacheattr;\r\nextern const unsigned char Xthal_have_tlbs;\r\n\r\nextern const unsigned char Xthal_mmu_asid_bits;\t\t/* 0 .. 8 */\r\nextern const unsigned char Xthal_mmu_asid_kernel;\r\nextern const unsigned char Xthal_mmu_rings;\t\t/* 1 .. 4 (perhaps 0 if no MMU and/or no protection?) */\r\nextern const unsigned char Xthal_mmu_ring_bits;\r\nextern const unsigned char Xthal_mmu_sr_bits;\r\nextern const unsigned char Xthal_mmu_ca_bits;\r\nextern const unsigned int  Xthal_mmu_max_pte_page_size;\r\nextern const unsigned int  Xthal_mmu_min_pte_page_size;\r\n\r\nextern const unsigned char Xthal_itlb_way_bits;\r\nextern const unsigned char Xthal_itlb_ways;\r\nextern const unsigned char Xthal_itlb_arf_ways;\r\nextern const unsigned char Xthal_dtlb_way_bits;\r\nextern const unsigned char Xthal_dtlb_ways;\r\nextern const unsigned char Xthal_dtlb_arf_ways;\r\n\r\n/*  Convert between virtual and physical addresses (through static maps only):  */\r\n/*** WARNING: these two functions may go away in a future release; don't depend on them! ***/\r\nextern int  xthal_static_v2p( unsigned vaddr, unsigned *paddrp );\r\nextern int  xthal_static_p2v( unsigned paddr, unsigned *vaddrp, unsigned cached );\r\n\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */\r\n\r\n#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */\r\n\r\n\r\n\r\n\r\n/****************************************************************************\r\n\t\tEXPERIMENTAL and DEPRECATED Definitions\r\n ****************************************************************************/\r\n\r\n\r\n#if !defined(_ASMLANGUAGE) && !defined(_NOCLANGUAGE) && !defined(__ASSEMBLER__)\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n#ifdef INCLUDE_DEPRECATED_HAL_CODE\r\nextern const unsigned char Xthal_have_old_exc_arch;\r\nextern const unsigned char Xthal_have_mmu;\r\nextern const unsigned int  Xthal_num_regs;\r\nextern const unsigned char Xthal_num_iroms;\r\nextern const unsigned char Xthal_num_irams;\r\nextern const unsigned char Xthal_num_droms;\r\nextern const unsigned char Xthal_num_drams;\r\nextern const unsigned int  Xthal_configid0;\r\nextern const unsigned int  Xthal_configid1;\r\n#endif\r\n\r\n#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE\r\n#define XTHAL_24_BIT_BREAK\t\t0x80000000\r\n#define XTHAL_16_BIT_BREAK\t\t0x40000000\r\nextern const unsigned short\tXthal_ill_inst_16[16];\r\n#define XTHAL_DEST_REG\t\t0xf0000000\t/* Mask for destination register */\r\n#define XTHAL_DEST_REG_INST\t0x08000000\t/* Branch address is in register */\r\n#define XTHAL_DEST_REL_INST\t0x04000000\t/* Branch address is relative */\r\n#define XTHAL_RFW_INST\t\t0x00000800\r\n#define XTHAL_RFUE_INST\t\t0x00000400\r\n#define XTHAL_RFI_INST\t\t0x00000200\r\n#define XTHAL_RFE_INST\t\t0x00000100\r\n#define XTHAL_RET_INST\t\t0x00000080\r\n#define XTHAL_BREAK_INST\t0x00000040\r\n#define XTHAL_SYSCALL_INST\t0x00000020\r\n#define XTHAL_LOOP_END\t\t0x00000010\t/* Not set by xthal_inst_type */\r\n#define XTHAL_JUMP_INST\t\t0x00000008\t/* Call or jump instruction */\r\n#define XTHAL_BRANCH_INST\t0x00000004\t/* Branch instruction */\r\n#define XTHAL_24_BIT_INST\t0x00000002\r\n#define XTHAL_16_BIT_INST   0x00000001\r\ntypedef struct xthal_state {\r\n    unsigned\tpc;\r\n    unsigned\tar[16];\r\n    unsigned\tlbeg;\r\n    unsigned\tlend;\r\n    unsigned\tlcount;\r\n    unsigned\textra_ptr;\r\n    unsigned\tcpregs_ptr[XTHAL_MAX_CPS];\r\n} XTHAL_STATE;\r\nextern unsigned int xthal_inst_type(void *addr);\r\nextern unsigned int xthal_branch_addr(void *addr);\r\nextern unsigned int xthal_get_npc(XTHAL_STATE *user_state);\r\n#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n#endif /*!_ASMLANGUAGE && !_NOCLANGUAGE && !__ASSEMBLER__ */\r\n\r\n#endif /*XTENSA_HAL_H*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/sim.h",
    "content": "/* Copyright (c) 2004-2006 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n/  These coded instructions, statements, and computer programs are the\r\n/  copyrighted works and confidential proprietary information of Tensilica Inc.\r\n/  They may not be modified, copied, reproduced, distributed, or disclosed to\r\n/  third parties in any manner, medium, or form, in whole or in part, without\r\n/  the prior written consent of Tensilica Inc.\r\n*/\r\n\r\n/*  sim.h \r\n *\r\n *  Definitions and prototypes for specific ISS SIMCALLs\r\n *  (ie. outside the standard C library).\r\n */\r\n\r\n#ifndef _INC_SIM_H_\r\n#define _INC_SIM_H_\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n/* Shortcuts for enabling/disabling profiling in the Xtensa ISS  */\r\nextern void xt_iss_profile_enable(void);\r\nextern void xt_iss_profile_disable(void);\r\n\r\n/* Shortcut for setting the trace level in the Xtensa ISS */\r\nextern void xt_iss_trace_level(unsigned level);\r\n\r\n/* Generic interface for passing client commands in the Xtensa ISS:\r\n *   returns 0 on success, -1 on failure.\r\n */\r\nextern int xt_iss_client_command(const char *client, const char *command);\r\n\r\n/* Interface for switching simulation modes in the Xtensa ISS:\r\n *   returns 0 on success, -1 on failure.\r\n */\r\n#define XT_ISS_CYCLE_ACCURATE 0\r\n#define XT_ISS_FUNCTIONAL     1\r\nextern int xt_iss_switch_mode(int mode);\r\n\r\n\r\n/* Interface for waiting on a system synchronization event */\r\nextern void xt_iss_event_wait(unsigned event_id);\r\n\r\n/* Interface for firing a system synchronization event */\r\nextern void xt_iss_event_fire(unsigned event_id);\r\n\r\n/* Interface for invoking a user simcall action,\r\n * which can be registered in XTMP or XTSC.\r\n */\r\nextern int xt_iss_simcall(int arg1, int arg2, int arg3,\r\n                          int arg4, int arg5, int arg6);\r\n\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif /*_INC_SIM_H_*/\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/simcall-errno.h",
    "content": "/* Error numbers for Xtensa ISS semihosting.  */\r\n\r\n/* Copyright (c) 2003 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n   These coded instructions, statements, and computer programs are the\r\n   copyrighted works and confidential proprietary information of Tensilica Inc.\r\n   They may not be modified, copied, reproduced, distributed, or disclosed to\r\n   third parties in any manner, medium, or form, in whole or in part, without\r\n   the prior written consent of Tensilica Inc.  */\r\n\r\n#ifndef _SIMCALL_ERRNO_H\r\n#define _SIMCALL_ERRNO_H\r\n\r\n/* Define the error numbers (using the default newlib values) with prefixes\r\n   so they can be used in ISS without conflicting with the host values.  */\r\n\r\n#define\t_SIMC_EPERM\t1\r\n#define\t_SIMC_ENOENT\t2\r\n#define\t_SIMC_ESRCH\t3\r\n#define\t_SIMC_EINTR\t4\r\n#define\t_SIMC_EIO\t5\r\n#define\t_SIMC_ENXIO\t6\r\n#define\t_SIMC_E2BIG\t7\r\n#define\t_SIMC_ENOEXEC\t8\r\n#define\t_SIMC_EBADF\t9\r\n#define\t_SIMC_ECHILD\t10\r\n#define\t_SIMC_EAGAIN\t11\r\n#define\t_SIMC_ENOMEM\t12\r\n#define\t_SIMC_EACCES\t13\r\n#define\t_SIMC_EFAULT\t14\r\n#define\t_SIMC_ENOTBLK\t15\r\n#define\t_SIMC_EBUSY\t16\r\n#define\t_SIMC_EEXIST\t17\r\n#define\t_SIMC_EXDEV\t18\r\n#define\t_SIMC_ENODEV\t19\r\n#define\t_SIMC_ENOTDIR\t20\r\n#define\t_SIMC_EISDIR\t21\r\n#define\t_SIMC_EINVAL\t22\r\n#define\t_SIMC_ENFILE\t23\r\n#define\t_SIMC_EMFILE\t24\r\n#define\t_SIMC_ENOTTY\t25\r\n#define\t_SIMC_ETXTBSY\t26\r\n#define\t_SIMC_EFBIG\t27\r\n#define\t_SIMC_ENOSPC\t28\r\n#define\t_SIMC_ESPIPE\t29\r\n#define\t_SIMC_EROFS\t30\r\n#define\t_SIMC_EMLINK\t31\r\n#define\t_SIMC_EPIPE\t32\r\n#define\t_SIMC_EDOM\t33\r\n#define\t_SIMC_ERANGE\t34\r\n#define\t_SIMC_ENOMSG\t35\r\n#define\t_SIMC_EIDRM\t36\r\n#define\t_SIMC_ECHRNG\t37\r\n#define\t_SIMC_EL2NSYNC\t38\r\n#define\t_SIMC_EL3HLT\t39\r\n#define\t_SIMC_EL3RST\t40\r\n#define\t_SIMC_ELNRNG\t41\r\n#define\t_SIMC_EUNATCH\t42\r\n#define\t_SIMC_ENOCSI\t43\r\n#define\t_SIMC_EL2HLT\t44\r\n#define\t_SIMC_EDEADLK\t45\r\n#define\t_SIMC_ENOLCK\t46\r\n#define _SIMC_EBADE\t50\r\n#define _SIMC_EBADR\t51\r\n#define _SIMC_EXFULL\t52\r\n#define _SIMC_ENOANO\t53\r\n#define _SIMC_EBADRQC\t54\r\n#define _SIMC_EBADSLT\t55\r\n#define _SIMC_EDEADLOCK\t56\r\n#define _SIMC_EBFONT\t57\r\n#define _SIMC_ENOSTR\t60\r\n#define _SIMC_ENODATA\t61\r\n#define _SIMC_ETIME\t62\r\n#define _SIMC_ENOSR\t63\r\n#define _SIMC_ENONET\t64\r\n#define _SIMC_ENOPKG\t65\r\n#define _SIMC_EREMOTE\t66\r\n#define _SIMC_ENOLINK\t67\r\n#define _SIMC_EADV\t68\r\n#define _SIMC_ESRMNT\t69\r\n#define\t_SIMC_ECOMM\t70\r\n#define _SIMC_EPROTO\t71\r\n#define\t_SIMC_EMULTIHOP\t74\r\n#define\t_SIMC_ELBIN\t75\r\n#define\t_SIMC_EDOTDOT\t76\r\n#define _SIMC_EBADMSG\t77\r\n#define _SIMC_EFTYPE\t79\r\n#define _SIMC_ENOTUNIQ\t80\r\n#define _SIMC_EBADFD\t81\r\n#define _SIMC_EREMCHG\t82\r\n#define _SIMC_ELIBACC\t83\r\n#define _SIMC_ELIBBAD\t84\r\n#define _SIMC_ELIBSCN\t85\r\n#define _SIMC_ELIBMAX\t86\r\n#define _SIMC_ELIBEXEC\t87\r\n#define _SIMC_ENOSYS\t88\r\n#define\t_SIMC_ENMFILE\t89\r\n#define _SIMC_ENOTEMPTY 90\r\n#define _SIMC_ENAMETOOLONG 91\r\n#define _SIMC_ELOOP 92\r\n#define _SIMC_EOPNOTSUPP 95\r\n#define _SIMC_EPFNOSUPPORT 96\r\n#define _SIMC_ECONNRESET 104\r\n#define _SIMC_ENOBUFS 105\r\n#define _SIMC_EAFNOSUPPORT 106\r\n#define _SIMC_EPROTOTYPE 107\r\n#define _SIMC_ENOTSOCK 108\r\n#define _SIMC_ENOPROTOOPT 109\r\n#define _SIMC_ESHUTDOWN 110\r\n#define _SIMC_ECONNREFUSED 111\r\n#define _SIMC_EADDRINUSE 112\r\n#define _SIMC_ECONNABORTED 113\r\n#define _SIMC_ENETUNREACH 114\r\n#define _SIMC_ENETDOWN 115\r\n#define _SIMC_ETIMEDOUT 116\r\n#define _SIMC_EHOSTDOWN 117\r\n#define _SIMC_EHOSTUNREACH 118\r\n#define _SIMC_EINPROGRESS 119\r\n#define _SIMC_EALREADY 120\r\n#define _SIMC_EDESTADDRREQ 121\r\n#define _SIMC_EMSGSIZE 122\r\n#define _SIMC_EPROTONOSUPPORT 123\r\n#define _SIMC_ESOCKTNOSUPPORT 124\r\n#define _SIMC_EADDRNOTAVAIL 125\r\n#define _SIMC_ENETRESET 126\r\n#define _SIMC_EISCONN 127\r\n#define _SIMC_ENOTCONN 128\r\n#define _SIMC_ETOOMANYREFS 129\r\n#define\t_SIMC_EPROCLIM 130\r\n#define _SIMC_EUSERS 131\r\n#define _SIMC_EDQUOT 132\r\n#define _SIMC_ESTALE 133\r\n#define _SIMC_ENOTSUP 134\r\n#define _SIMC_ENOMEDIUM 135\r\n#define\t_SIMC_ENOSHARE 136\r\n#define\t_SIMC_ECASECLASH 137\r\n#define _SIMC_EILSEQ 138\r\n#define _SIMC_EOVERFLOW 139\r\n\r\n#endif /* ! _SIMCALL_ERRNO_H */\r\n"
  },
  {
    "path": "app/include/xtensa/simcall-fcntl.h",
    "content": "/* File control operations for Xtensa ISS semihosting.  */\r\n\r\n/* Copyright (c) 2003 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n   These coded instructions, statements, and computer programs are the\r\n   copyrighted works and confidential proprietary information of Tensilica Inc.\r\n   They may not be modified, copied, reproduced, distributed, or disclosed to\r\n   third parties in any manner, medium, or form, in whole or in part, without\r\n   the prior written consent of Tensilica Inc.  */\r\n\r\n#ifndef _SIMCALL_FCNTL_H\r\n#define _SIMCALL_FCNTL_H\r\n\r\n#define\t_SIMC_O_APPEND\t\t0x0008\r\n#define\t_SIMC_O_NONBLOCK\t0x0080\r\n#define\t_SIMC_O_CREAT\t\t0x0100\r\n#define\t_SIMC_O_TRUNC\t\t0x0200\r\n#define\t_SIMC_O_EXCL\t\t0x0400\r\n#define _SIMC_O_TEXT\t\t0x4000\r\n#define _SIMC_O_BINARY\t\t0x8000\r\n\r\n#endif /* ! _SIMCALL_FCNTL_H */\r\n"
  },
  {
    "path": "app/include/xtensa/simcall.h",
    "content": "/*\r\n *  simcall.h  -  Simulator call numbers\r\n *\r\n *  Software that runs on a simulated Xtensa processor using\r\n *  the instruction set simulator (ISS) can invoke simulator\r\n *  services using the SIMCALL instruction.  The a2 register\r\n *  is set prior to executing SIMCALL to a \"simcall number\",\r\n *  indicating which service to invoke.  This file defines the\r\n *  simcall numbers defined and/or supported by the Xtensa ISS.\r\n *\r\n *  IMPORTANT NOTE:  These numbers are highly subject to change!\r\n *\r\n *  Copyright (c) 2002-2007 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n *  These coded instructions, statements, and computer programs are the\r\n *  copyrighted works and confidential proprietary information of Tensilica Inc.\r\n *  They may not be modified, copied, reproduced, distributed, or disclosed to\r\n *  third parties in any manner, medium, or form, in whole or in part, without\r\n *  the prior written consent of Tensilica Inc.\r\n */\r\n\r\n#ifndef SIMCALL_INCLUDED\r\n#define SIMCALL_INCLUDED\r\n\r\n/*\r\n *  System call like services offered by the simulator host.\r\n *  These are modeled after the Linux 2.4 kernel system calls\r\n *  for Xtensa processors.  However not all system calls and\r\n *  not all functionality of a given system call are implemented,\r\n *  or necessarily have well defined or equivalent semantics in\r\n *  the context of a simulation (as opposed to a Unix kernel).\r\n *\r\n *  These services behave largely as if they had been invoked\r\n *  as a task in the simulator host's operating system\r\n *  (eg. files accessed are those of the simulator host).\r\n *  However, these SIMCALLs model a virtual operating system\r\n *  so that various definitions, bit assignments etc\r\n *  (eg. open mode bits, errno values, etc) are independent\r\n *  of the host operating system used to run the simulation.\r\n *  Rather these definitions are specific to the Xtensa ISS.\r\n *  This way Xtensa ISA code written to use these SIMCALLs\r\n *  can (in principle) be simulated on any host.\r\n *\r\n *  Up to 6 parameters are passed in registers a3 to a8\r\n *  (note the 6th parameter isn't passed on the stack,\r\n *   unlike windowed function calling conventions).\r\n *  The return value is in a2.  A negative value in the\r\n *  range -4096 to -1 indicates a negated error code to be\r\n *  reported in errno with a return value of -1, otherwise\r\n *  the value in a2 is returned as is.\r\n */\r\n\r\n/* These #defines need to match what's in Xtensa/OS/vxworks/xtiss/simcalls.c */\r\n\r\n#define SYS_nop\t\t0\t/* n/a - setup; used to flush register windows */\r\n#define SYS_exit\t1\t/*x*/\r\n#define SYS_fork\t2\r\n#define SYS_read\t3\t/*x*/\r\n#define SYS_write\t4\t/*x*/\r\n#define SYS_open\t5\t/*x*/\r\n#define SYS_close\t6\t/*x*/\r\n#define SYS_rename\t7\t/*x 38 - waitpid */\r\n#define SYS_creat\t8\t/*x*/\r\n#define SYS_link\t9\t/*x (not implemented on WIN32) */\r\n#define SYS_unlink\t10\t/*x*/\r\n#define SYS_execv\t11\t/* n/a - execve */\r\n#define SYS_execve\t12\t/* 11 - chdir */\r\n#define SYS_pipe\t13\t/* 42 - time */\r\n#define SYS_stat\t14\t/* 106 - mknod */\r\n#define SYS_chmod\t15\r\n#define SYS_chown\t16\t/* 202 - lchown */\r\n#define SYS_utime\t17\t/* 30 - break */\r\n#define SYS_wait\t18\t/* n/a - oldstat */\r\n#define SYS_lseek\t19\t/*x*/\r\n#define SYS_getpid\t20\r\n#define SYS_isatty\t21\t/* n/a - mount */\r\n#define SYS_fstat\t22\t/* 108 - oldumount */\r\n#define SYS_time\t23\t/* 13 - setuid */\r\n#define SYS_gettimeofday 24\t/*x 78 - getuid (not implemented on WIN32) */\r\n#define SYS_times\t25\t/*X 43 - stime (Xtensa-specific implementation) */\r\n#define SYS_socket      26\r\n#define SYS_sendto      27\r\n#define SYS_recvfrom    28\r\n#define SYS_select_one  29      /* not compitible select, one file descriptor at the time */\r\n#define SYS_bind        30\r\n#define SYS_ioctl       31\r\n\r\n/*\r\n *  Other...\r\n */\r\n#define SYS_iss_argc         1000 /* returns value of argc */\r\n#define SYS_iss_argv_size    1001 /* bytes needed for argv & arg strings */\r\n#define SYS_iss_set_argv     1002 /* saves argv & arg strings at given addr */\r\n\r\n#define SYS_memset           1004 /* fill a range of memory (fast) */\r\n\r\n/*\r\n * SIMCALLs for the ferret memory debugger. All are invoked by\r\n * libferret.a ...  ( Xtensa/Target-Libs/ferret )\r\n */\r\n#define SYS_ferret           1010\r\n#define SYS_malloc           1011\r\n#define SYS_free             1012\r\n#define SYS_more_heap        1013\r\n#define SYS_no_heap          1014\r\n#define SYS_enter_ferret     1015\r\n#define SYS_leave_ferret     1016\r\n\r\n/*\r\n * SIMCALLs for ISS client commands\r\n */\r\n#define SYS_profile_enable   1020\r\n#define SYS_profile_disable  1021\r\n#define SYS_trace_level      1022\r\n#define SYS_client_command   1023\r\n\r\n/*\r\n * SIMCALL for simulation mode switching\r\n */\r\n#define SYS_sim_mode_switch  1030\r\n\r\n/*\r\n * SIMCALLs for XTMP/XTSC event notify and core stall\r\n */\r\n#define SYS_event_fire       1040\r\n#define SYS_event_stall      1041\r\n\r\n/*\r\n *  SIMCALLs for callbacks registered in XTMP/XTSC\r\n */\r\n#define SYS_callback_first      100\r\n#define SYS_callback_last       999\r\n\r\n/*\r\n * User defined simcall \r\n */\r\n#define SYS_user_simcall        100\r\n\r\n#define SYS_xmpa_errinfo        200\r\n#define SYS_xmpa_proc_status    201\r\n#define SYS_xmpa_proc_start     202\r\n#define SYS_xmpa_proc_stop      203\r\n#define SYS_xmpa_proc_mem_read  204\r\n#define SYS_xmpa_proc_mem_write 205\r\n#define SYS_xmpa_proc_mem_fill  206\r\n#define SYS_xmpa_proc_reg_read  207\r\n#define SYS_xmpa_proc_reg_write 208\r\n\r\n\r\n/*\r\n *  Extra SIMCALLs for GDB:\r\n */\r\n#define SYS_gdb_break         -1\t/* invoked by XTOS on user exceptions if EPC points\r\n\t\t\t\t\t   to a break.n/break, regardless of cause! */\r\n#define SYS_xmon_out          -2\t/* invoked by XMON: ... */\r\n#define SYS_xmon_in           -3\t/* invoked by XMON: ... */\r\n#define SYS_xmon_flush        -4\t/* invoked by XMON: ... */\r\n#define SYS_gdb_abort         -5\t/* invoked by XTOS in _xtos_panic() */\r\n#define SYS_gdb_illegal_inst  -6\t/* invoked by XTOS for illegal instructions (too deeply) */\r\n#define SYS_xmon_init         -7\t/* invoked by XMON: ... */\r\n#define SYS_gdb_enter_sktloop -8\t/* invoked by XTOS on debug exceptions */\r\n#define SYS_unhandled_kernel_exc  -9\t/* invoked by XTOS for unhandled kernel exceptions */\r\n#define SYS_unhandled_user_exc   -10\t/* invoked by XTOS for unhandled user exceptions */\r\n#define SYS_unhandled_double_exc -11\t/* invoked by XTOS for unhandled double exceptions */\r\n#define SYS_unhandled_highpri_interrupt -12\t/* invoked by XTOS for unhandled high-priority interrupts */\r\n\r\n/*\r\n *  SIMCALLs for vxWorks xtiss BSP:\r\n */\r\n#define SYS_setup_ppp_pipes   -83\r\n#define SYS_log_msg           -84\r\n\r\n/*\r\n * SYS_select_one specifiers \r\n */\r\n#define  XTISS_SELECT_ONE_READ    1\r\n#define  XTISS_SELECT_ONE_WRITE   2\r\n#define  XTISS_SELECT_ONE_EXCEPT  3\r\n\r\n/*\r\n * SIMCALL for client calling arbitrary code in a client plug in.\r\n * see clients/xcc_instr to see how this works.\r\n */\r\n\r\n#define SYS_client           0xC0DECAFE\r\n\r\n\r\n\r\n#endif /* !SIMCALL_INCLUDED */\r\n"
  },
  {
    "path": "app/include/xtensa/specreg.h",
    "content": "/*\r\n * Xtensa Special Register symbolic names\r\n */\r\n\r\n/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/specreg.h#2 $ */\r\n\r\n/*\r\n * Copyright (c) 2005-2010 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef XTENSA_SPECREG_H\r\n#define XTENSA_SPECREG_H\r\n\r\n/*  Special registers:  */\r\n#define LBEG\t\t0\r\n#define LEND\t\t1\r\n#define LCOUNT\t\t2\r\n#define SAR\t\t3\r\n#define BR\t\t4\r\n#define LITBASE\t\t5\r\n#define SCOMPARE1\t12\r\n#define ACCLO\t\t16\r\n#define ACCHI\t\t17\r\n#define MR_0\t\t32\r\n#define MR_1\t\t33\r\n#define MR_2\t\t34\r\n#define MR_3\t\t35\r\n#define PREFCTL\t\t40\r\n#define WINDOWBASE\t72\r\n#define WINDOWSTART\t73\r\n#define PTEVADDR\t83\r\n#define RASID\t\t90\r\n#define ITLBCFG\t\t91\r\n#define DTLBCFG\t\t92\r\n#define IBREAKENABLE\t96\r\n#define CACHEATTR\t98\r\n#define DDR\t\t104\r\n#define IBREAKA_0\t128\r\n#define IBREAKA_1\t129\r\n#define DBREAKA_0\t144\r\n#define DBREAKA_1\t145\r\n#define DBREAKC_0\t160\r\n#define DBREAKC_1\t161\r\n#define EPC_1\t\t177\r\n#define EPC_2\t\t178\r\n#define EPC_3\t\t179\r\n#define EPC_4\t\t180\r\n#define EPC_5\t\t181\r\n#define EPC_6\t\t182\r\n#define EPC_7\t\t183\r\n#define DEPC\t\t192\r\n#define EPS_2\t\t194\r\n#define EPS_3\t\t195\r\n#define EPS_4\t\t196\r\n#define EPS_5\t\t197\r\n#define EPS_6\t\t198\r\n#define EPS_7\t\t199\r\n#define EXCSAVE_1\t209\r\n#define EXCSAVE_2\t210\r\n#define EXCSAVE_3\t211\r\n#define EXCSAVE_4\t212\r\n#define EXCSAVE_5\t213\r\n#define EXCSAVE_6\t214\r\n#define EXCSAVE_7\t215\r\n#define CPENABLE\t224\r\n#define INTERRUPT\t226\r\n#define INTREAD\t\tINTERRUPT\t/* alternate name for backward compatibility */\r\n#define INTSET\t\tINTERRUPT\t/* alternate name for backward compatibility */\r\n#define INTCLEAR\t227\r\n#define INTENABLE\t228\r\n#define PS\t\t230\r\n#define VECBASE\t\t231\r\n#define EXCCAUSE\t232\r\n#define DEBUGCAUSE\t233\r\n#define CCOUNT\t\t234\r\n#define PRID\t\t235\r\n#define ICOUNT\t\t236\r\n#define ICOUNTLEVEL\t237\r\n#define EXCVADDR\t238\r\n#define CCOMPARE_0\t240\r\n#define CCOMPARE_1\t241\r\n#define CCOMPARE_2\t242\r\n#define MISC_REG_0\t244\r\n#define MISC_REG_1\t245\r\n#define MISC_REG_2\t246\r\n#define MISC_REG_3\t247\r\n\r\n/*  Special cases (bases of special register series):  */\r\n#define MR\t\t32\r\n#define IBREAKA\t\t128\r\n#define DBREAKA\t\t144\r\n#define DBREAKC\t\t160\r\n#define EPC\t\t176\r\n#define EPS\t\t192\r\n#define EXCSAVE\t\t208\r\n#define CCOMPARE\t240\r\n#define MISC_REG\t244\r\n\r\n/*  Tensilica-defined user registers:  */\r\n#if 0\r\n/*#define ...\t 21..24 */\t/* (545CK) */\r\n/*#define ...\t140..143 */\t/* (545CK) */\r\n#define EXPSTATE\t230\t/* Diamond */\r\n#define THREADPTR\t231\t/* threadptr option */\r\n#define FCR\t\t232\t/* FPU */\r\n#define FSR\t\t233\t/* FPU */\r\n#define AE_OVF_SAR\t240\t/* HiFi2 */\r\n#define AE_BITHEAD\t241\t/* HiFi2 */\r\n#define AE_TS_FTS_BU_BP\t242\t/* HiFi2 */\r\n#define AE_SD_NO\t243\t/* HiFi2 */\r\n#define VSAR\t\t240\t/* VectraLX */\r\n#define ROUND_LO\t242\t/* VectraLX */\r\n#define ROUND_HI\t243\t/* VectraLX */\r\n#define CBEGIN\t\t246\t/* VectraLX */\r\n#define CEND\t\t247\t/* VectraLX */\r\n#endif\r\n\r\n#endif /* XTENSA_SPECREG_H */\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_MUL32.h",
    "content": "/* Definitions for the 32-bit Integer Multiply Option. */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2009 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* NOTE: This file exists only for backward compatibility with RB-200X.x\r\n   and earlier Xtensa releases.  Starting with RC-2009.0 you should use \r\n   <xtensa/tie/xt_mul.h>.  */\r\n\r\n#ifndef _XTENSA_xt_MUL32_HEADER\r\n#define _XTENSA_xt_MUL32_HEADER\r\n\r\n#ifdef __XTENSA__\r\n\r\n#include <xtensa/tie/xt_mul.h>\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_MUL32_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_core.h",
    "content": "/* Definitions for the xt_core TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_core_HEADER\r\n#define _XTENSA_xt_core_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern void _TIE_xt_core_ILL(void);\r\nextern void _TIE_xt_core_NOP(void);\r\nextern void _TIE_xt_core_MEMW(void);\r\nextern void _TIE_xt_core_EXTW(void);\r\nextern void _TIE_xt_core_ISYNC(void);\r\nextern void _TIE_xt_core_DSYNC(void);\r\nextern void _TIE_xt_core_ESYNC(void);\r\nextern void _TIE_xt_core_RSYNC(void);\r\nextern unsigned _TIE_xt_core_RSR_176(void);\r\nextern void _TIE_xt_core_WSR_176(unsigned art);\r\nextern unsigned _TIE_xt_core_RSR_208(void);\r\nextern unsigned _TIE_xt_core_uint32_loadi(const unsigned * p, immediate o);\r\nextern void _TIE_xt_core_uint32_storei(unsigned c, unsigned * p, immediate o);\r\nextern unsigned _TIE_xt_core_uint32_move(unsigned b);\r\nextern int _TIE_xt_core_ADDI(int s, immediate i);\r\nextern int _TIE_xt_core_OR(int s, int t);\r\nextern int _TIE_xt_core_L32I(const int * p, immediate i);\r\nextern void _TIE_xt_core_S32I(int r, int * p, immediate i);\r\nextern unsigned char _TIE_xt_core_L8UI(const unsigned char * p, immediate i);\r\nextern void _TIE_xt_core_S8I(signed char r, signed char * p, immediate i);\r\nextern unsigned short _TIE_xt_core_L16UI(const unsigned short * p, immediate i);\r\nextern short _TIE_xt_core_L16SI(const short * p, immediate i);\r\nextern void _TIE_xt_core_S16I(short r, short * p, immediate i);\r\nextern int _TIE_xt_core_ADDMI(int s, immediate i);\r\nextern int _TIE_xt_core_ADD(int s, int t);\r\nextern int _TIE_xt_core_ADDX2(int s, int t);\r\nextern int _TIE_xt_core_ADDX4(int s, int t);\r\nextern int _TIE_xt_core_ADDX8(int s, int t);\r\nextern int _TIE_xt_core_SUB(int s, int t);\r\nextern int _TIE_xt_core_SUBX2(int s, int t);\r\nextern int _TIE_xt_core_SUBX4(int s, int t);\r\nextern int _TIE_xt_core_SUBX8(int s, int t);\r\nextern int _TIE_xt_core_AND(int s, int t);\r\nextern int _TIE_xt_core_XOR(int s, int t);\r\nextern unsigned _TIE_xt_core_EXTUI(unsigned t, immediate i, immediate o);\r\nextern int _TIE_xt_core_MOVI(immediate i);\r\nextern void _TIE_xt_core_MOVEQZ(int r /*inout*/, int s, int t);\r\nextern void _TIE_xt_core_MOVNEZ(int r /*inout*/, int s, int t);\r\nextern void _TIE_xt_core_MOVLTZ(int r /*inout*/, int s, int t);\r\nextern void _TIE_xt_core_MOVGEZ(int r /*inout*/, int s, int t);\r\nextern int _TIE_xt_core_NEG(int t);\r\nextern int _TIE_xt_core_ABS(int t);\r\nextern void _TIE_xt_core_SSR(int s);\r\nextern void _TIE_xt_core_SSL(int s);\r\nextern void _TIE_xt_core_SSA8L(int s);\r\nextern void _TIE_xt_core_SSA8B(int s);\r\nextern void _TIE_xt_core_SSAI(immediate i);\r\nextern int _TIE_xt_core_SLL(int s);\r\nextern int _TIE_xt_core_SRC(int s, int t);\r\nextern unsigned _TIE_xt_core_SRL(unsigned t);\r\nextern int _TIE_xt_core_SRA(int t);\r\nextern int _TIE_xt_core_SLLI(int s, immediate i);\r\nextern int _TIE_xt_core_SRAI(int t, immediate i);\r\nextern unsigned _TIE_xt_core_SRLI(unsigned t, immediate i);\r\nextern int _TIE_xt_core_SSAI_SRC(int src1, int src2, immediate amount);\r\nextern int _TIE_xt_core_SSR_SRC(int src1, int src2, int amount);\r\nextern int _TIE_xt_core_WSR_SAR_SRC(int src1, int src2, int amount);\r\nextern int _TIE_xt_core_SSR_SRA(int src, int amount);\r\nextern unsigned _TIE_xt_core_SSR_SRL(unsigned src, int amount);\r\nextern int _TIE_xt_core_SSL_SLL(int src, int amount);\r\nextern int _TIE_xt_core_RSIL(immediate t);\r\nextern unsigned _TIE_xt_core_RSR_SAR(void);\r\nextern void _TIE_xt_core_WSR_SAR(unsigned t);\r\nextern void _TIE_xt_core_XSR_SAR(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_LITBASE(void);\r\nextern void _TIE_xt_core_WSR_LITBASE(unsigned t);\r\nextern void _TIE_xt_core_XSR_LITBASE(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_PS(void);\r\nextern void _TIE_xt_core_WSR_PS(unsigned t);\r\nextern void _TIE_xt_core_XSR_PS(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EPC1(void);\r\nextern void _TIE_xt_core_WSR_EPC1(unsigned t);\r\nextern void _TIE_xt_core_XSR_EPC1(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EXCSAVE1(void);\r\nextern void _TIE_xt_core_WSR_EXCSAVE1(unsigned t);\r\nextern void _TIE_xt_core_XSR_EXCSAVE1(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EPC2(void);\r\nextern void _TIE_xt_core_WSR_EPC2(unsigned t);\r\nextern void _TIE_xt_core_XSR_EPC2(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EXCSAVE2(void);\r\nextern void _TIE_xt_core_WSR_EXCSAVE2(unsigned t);\r\nextern void _TIE_xt_core_XSR_EXCSAVE2(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EPC3(void);\r\nextern void _TIE_xt_core_WSR_EPC3(unsigned t);\r\nextern void _TIE_xt_core_XSR_EPC3(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EXCSAVE3(void);\r\nextern void _TIE_xt_core_WSR_EXCSAVE3(unsigned t);\r\nextern void _TIE_xt_core_XSR_EXCSAVE3(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_VECBASE(void);\r\nextern void _TIE_xt_core_WSR_VECBASE(unsigned t);\r\nextern void _TIE_xt_core_XSR_VECBASE(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EPS2(void);\r\nextern void _TIE_xt_core_WSR_EPS2(unsigned t);\r\nextern void _TIE_xt_core_XSR_EPS2(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EPS3(void);\r\nextern void _TIE_xt_core_WSR_EPS3(unsigned t);\r\nextern void _TIE_xt_core_XSR_EPS3(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EXCCAUSE(void);\r\nextern void _TIE_xt_core_WSR_EXCCAUSE(unsigned t);\r\nextern void _TIE_xt_core_XSR_EXCCAUSE(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_EXCVADDR(void);\r\nextern void _TIE_xt_core_WSR_EXCVADDR(unsigned t);\r\nextern void _TIE_xt_core_XSR_EXCVADDR(unsigned t /*inout*/);\r\nextern unsigned _TIE_xt_core_RSR_DEPC(void);\r\nextern void _TIE_xt_core_WSR_DEPC(unsigned t);\r\nextern void _TIE_xt_core_XSR_DEPC(unsigned t /*inout*/);\r\nextern int _TIE_xt_core_RSR_PRID(void);\r\n#define XT_ILL _TIE_xt_core_ILL\r\n#define XT_NOP _TIE_xt_core_NOP\r\n#define XT_MEMW _TIE_xt_core_MEMW\r\n#define XT_EXTW _TIE_xt_core_EXTW\r\n#define XT_ISYNC _TIE_xt_core_ISYNC\r\n#define XT_DSYNC _TIE_xt_core_DSYNC\r\n#define XT_ESYNC _TIE_xt_core_ESYNC\r\n#define XT_RSYNC _TIE_xt_core_RSYNC\r\n#define XT_RSR_176 _TIE_xt_core_RSR_176\r\n#define XT_WSR_176 _TIE_xt_core_WSR_176\r\n#define XT_RSR_208 _TIE_xt_core_RSR_208\r\n#define XT_uint32_loadi _TIE_xt_core_uint32_loadi\r\n#define XT_uint32_storei _TIE_xt_core_uint32_storei\r\n#define XT_uint32_move _TIE_xt_core_uint32_move\r\n#define XT_ADDI _TIE_xt_core_ADDI\r\n#define XT_OR _TIE_xt_core_OR\r\n#define XT_L32I _TIE_xt_core_L32I\r\n#define XT_S32I _TIE_xt_core_S32I\r\n#define XT_L8UI _TIE_xt_core_L8UI\r\n#define XT_S8I _TIE_xt_core_S8I\r\n#define XT_L16UI _TIE_xt_core_L16UI\r\n#define XT_L16SI _TIE_xt_core_L16SI\r\n#define XT_S16I _TIE_xt_core_S16I\r\n#define XT_ADDMI _TIE_xt_core_ADDMI\r\n#define XT_ADD _TIE_xt_core_ADD\r\n#define XT_ADDX2 _TIE_xt_core_ADDX2\r\n#define XT_ADDX4 _TIE_xt_core_ADDX4\r\n#define XT_ADDX8 _TIE_xt_core_ADDX8\r\n#define XT_SUB _TIE_xt_core_SUB\r\n#define XT_SUBX2 _TIE_xt_core_SUBX2\r\n#define XT_SUBX4 _TIE_xt_core_SUBX4\r\n#define XT_SUBX8 _TIE_xt_core_SUBX8\r\n#define XT_AND _TIE_xt_core_AND\r\n#define XT_XOR _TIE_xt_core_XOR\r\n#define XT_EXTUI _TIE_xt_core_EXTUI\r\n#define XT_MOVI _TIE_xt_core_MOVI\r\n#define XT_MOVEQZ _TIE_xt_core_MOVEQZ\r\n#define XT_MOVNEZ _TIE_xt_core_MOVNEZ\r\n#define XT_MOVLTZ _TIE_xt_core_MOVLTZ\r\n#define XT_MOVGEZ _TIE_xt_core_MOVGEZ\r\n#define XT_NEG _TIE_xt_core_NEG\r\n#define XT_ABS _TIE_xt_core_ABS\r\n#define XT_SSR _TIE_xt_core_SSR\r\n#define XT_SSL _TIE_xt_core_SSL\r\n#define XT_SSA8L _TIE_xt_core_SSA8L\r\n#define XT_SSA8B _TIE_xt_core_SSA8B\r\n#define XT_SSAI _TIE_xt_core_SSAI\r\n#define XT_SLL _TIE_xt_core_SLL\r\n#define XT_SRC _TIE_xt_core_SRC\r\n#define XT_SRL _TIE_xt_core_SRL\r\n#define XT_SRA _TIE_xt_core_SRA\r\n#define XT_SLLI _TIE_xt_core_SLLI\r\n#define XT_SRAI _TIE_xt_core_SRAI\r\n#define XT_SRLI _TIE_xt_core_SRLI\r\n#define XT_SSAI_SRC _TIE_xt_core_SSAI_SRC\r\n#define XT_SSR_SRC _TIE_xt_core_SSR_SRC\r\n#define XT_WSR_SAR_SRC _TIE_xt_core_WSR_SAR_SRC\r\n#define XT_SSR_SRA _TIE_xt_core_SSR_SRA\r\n#define XT_SSR_SRL _TIE_xt_core_SSR_SRL\r\n#define XT_SSL_SLL _TIE_xt_core_SSL_SLL\r\n#define XT_RSIL _TIE_xt_core_RSIL\r\n#define XT_RSR_SAR _TIE_xt_core_RSR_SAR\r\n#define XT_WSR_SAR _TIE_xt_core_WSR_SAR\r\n#define XT_XSR_SAR _TIE_xt_core_XSR_SAR\r\n#define XT_RSR_LITBASE _TIE_xt_core_RSR_LITBASE\r\n#define XT_WSR_LITBASE _TIE_xt_core_WSR_LITBASE\r\n#define XT_XSR_LITBASE _TIE_xt_core_XSR_LITBASE\r\n#define XT_RSR_PS _TIE_xt_core_RSR_PS\r\n#define XT_WSR_PS _TIE_xt_core_WSR_PS\r\n#define XT_XSR_PS _TIE_xt_core_XSR_PS\r\n#define XT_RSR_EPC1 _TIE_xt_core_RSR_EPC1\r\n#define XT_WSR_EPC1 _TIE_xt_core_WSR_EPC1\r\n#define XT_XSR_EPC1 _TIE_xt_core_XSR_EPC1\r\n#define XT_RSR_EXCSAVE1 _TIE_xt_core_RSR_EXCSAVE1\r\n#define XT_WSR_EXCSAVE1 _TIE_xt_core_WSR_EXCSAVE1\r\n#define XT_XSR_EXCSAVE1 _TIE_xt_core_XSR_EXCSAVE1\r\n#define XT_RSR_EPC2 _TIE_xt_core_RSR_EPC2\r\n#define XT_WSR_EPC2 _TIE_xt_core_WSR_EPC2\r\n#define XT_XSR_EPC2 _TIE_xt_core_XSR_EPC2\r\n#define XT_RSR_EXCSAVE2 _TIE_xt_core_RSR_EXCSAVE2\r\n#define XT_WSR_EXCSAVE2 _TIE_xt_core_WSR_EXCSAVE2\r\n#define XT_XSR_EXCSAVE2 _TIE_xt_core_XSR_EXCSAVE2\r\n#define XT_RSR_EPC3 _TIE_xt_core_RSR_EPC3\r\n#define XT_WSR_EPC3 _TIE_xt_core_WSR_EPC3\r\n#define XT_XSR_EPC3 _TIE_xt_core_XSR_EPC3\r\n#define XT_RSR_EXCSAVE3 _TIE_xt_core_RSR_EXCSAVE3\r\n#define XT_WSR_EXCSAVE3 _TIE_xt_core_WSR_EXCSAVE3\r\n#define XT_XSR_EXCSAVE3 _TIE_xt_core_XSR_EXCSAVE3\r\n#define XT_RSR_VECBASE _TIE_xt_core_RSR_VECBASE\r\n#define XT_WSR_VECBASE _TIE_xt_core_WSR_VECBASE\r\n#define XT_XSR_VECBASE _TIE_xt_core_XSR_VECBASE\r\n#define XT_RSR_EPS2 _TIE_xt_core_RSR_EPS2\r\n#define XT_WSR_EPS2 _TIE_xt_core_WSR_EPS2\r\n#define XT_XSR_EPS2 _TIE_xt_core_XSR_EPS2\r\n#define XT_RSR_EPS3 _TIE_xt_core_RSR_EPS3\r\n#define XT_WSR_EPS3 _TIE_xt_core_WSR_EPS3\r\n#define XT_XSR_EPS3 _TIE_xt_core_XSR_EPS3\r\n#define XT_RSR_EXCCAUSE _TIE_xt_core_RSR_EXCCAUSE\r\n#define XT_WSR_EXCCAUSE _TIE_xt_core_WSR_EXCCAUSE\r\n#define XT_XSR_EXCCAUSE _TIE_xt_core_XSR_EXCCAUSE\r\n#define XT_RSR_EXCVADDR _TIE_xt_core_RSR_EXCVADDR\r\n#define XT_WSR_EXCVADDR _TIE_xt_core_WSR_EXCVADDR\r\n#define XT_XSR_EXCVADDR _TIE_xt_core_XSR_EXCVADDR\r\n#define XT_RSR_DEPC _TIE_xt_core_RSR_DEPC\r\n#define XT_WSR_DEPC _TIE_xt_core_WSR_DEPC\r\n#define XT_XSR_DEPC _TIE_xt_core_XSR_DEPC\r\n#define XT_RSR_PRID _TIE_xt_core_RSR_PRID\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_core_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_debug.h",
    "content": "/* Definitions for the xt_debug TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_debug_HEADER\r\n#define _XTENSA_xt_debug_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern void _TIE_xt_debug_BREAK(immediate imms, immediate immt);\r\nextern void _TIE_xt_debug_BREAK_N(immediate imms);\r\nextern unsigned _TIE_xt_debug_RSR_DBREAKA0(void);\r\nextern void _TIE_xt_debug_WSR_DBREAKA0(unsigned art);\r\nextern void _TIE_xt_debug_XSR_DBREAKA0(unsigned art /*inout*/);\r\nextern unsigned _TIE_xt_debug_RSR_DBREAKC0(void);\r\nextern void _TIE_xt_debug_WSR_DBREAKC0(unsigned art);\r\nextern void _TIE_xt_debug_XSR_DBREAKC0(unsigned art /*inout*/);\r\nextern unsigned _TIE_xt_debug_RSR_IBREAKA0(void);\r\nextern void _TIE_xt_debug_WSR_IBREAKA0(unsigned art);\r\nextern void _TIE_xt_debug_XSR_IBREAKA0(unsigned art /*inout*/);\r\nextern unsigned _TIE_xt_debug_RSR_IBREAKENABLE(void);\r\nextern void _TIE_xt_debug_WSR_IBREAKENABLE(unsigned art);\r\nextern void _TIE_xt_debug_XSR_IBREAKENABLE(unsigned art /*inout*/);\r\nextern unsigned _TIE_xt_debug_RSR_DEBUGCAUSE(void);\r\nextern void _TIE_xt_debug_WSR_DEBUGCAUSE(unsigned art);\r\nextern void _TIE_xt_debug_XSR_DEBUGCAUSE(unsigned art /*inout*/);\r\nextern unsigned _TIE_xt_debug_RSR_ICOUNT(void);\r\nextern void _TIE_xt_debug_WSR_ICOUNT(unsigned art);\r\nextern void _TIE_xt_debug_XSR_ICOUNT(unsigned art /*inout*/);\r\nextern unsigned _TIE_xt_debug_RSR_ICOUNTLEVEL(void);\r\nextern void _TIE_xt_debug_WSR_ICOUNTLEVEL(unsigned art);\r\nextern void _TIE_xt_debug_XSR_ICOUNTLEVEL(unsigned art /*inout*/);\r\nextern unsigned _TIE_xt_debug_RSR_DDR(void);\r\nextern void _TIE_xt_debug_WSR_DDR(unsigned art);\r\nextern void _TIE_xt_debug_XSR_DDR(unsigned art /*inout*/);\r\n#define XT_BREAK _TIE_xt_debug_BREAK\r\n#define XT_BREAK_N _TIE_xt_debug_BREAK_N\r\n#define XT_RSR_DBREAKA0 _TIE_xt_debug_RSR_DBREAKA0\r\n#define XT_WSR_DBREAKA0 _TIE_xt_debug_WSR_DBREAKA0\r\n#define XT_XSR_DBREAKA0 _TIE_xt_debug_XSR_DBREAKA0\r\n#define XT_RSR_DBREAKC0 _TIE_xt_debug_RSR_DBREAKC0\r\n#define XT_WSR_DBREAKC0 _TIE_xt_debug_WSR_DBREAKC0\r\n#define XT_XSR_DBREAKC0 _TIE_xt_debug_XSR_DBREAKC0\r\n#define XT_RSR_IBREAKA0 _TIE_xt_debug_RSR_IBREAKA0\r\n#define XT_WSR_IBREAKA0 _TIE_xt_debug_WSR_IBREAKA0\r\n#define XT_XSR_IBREAKA0 _TIE_xt_debug_XSR_IBREAKA0\r\n#define XT_RSR_IBREAKENABLE _TIE_xt_debug_RSR_IBREAKENABLE\r\n#define XT_WSR_IBREAKENABLE _TIE_xt_debug_WSR_IBREAKENABLE\r\n#define XT_XSR_IBREAKENABLE _TIE_xt_debug_XSR_IBREAKENABLE\r\n#define XT_RSR_DEBUGCAUSE _TIE_xt_debug_RSR_DEBUGCAUSE\r\n#define XT_WSR_DEBUGCAUSE _TIE_xt_debug_WSR_DEBUGCAUSE\r\n#define XT_XSR_DEBUGCAUSE _TIE_xt_debug_XSR_DEBUGCAUSE\r\n#define XT_RSR_ICOUNT _TIE_xt_debug_RSR_ICOUNT\r\n#define XT_WSR_ICOUNT _TIE_xt_debug_WSR_ICOUNT\r\n#define XT_XSR_ICOUNT _TIE_xt_debug_XSR_ICOUNT\r\n#define XT_RSR_ICOUNTLEVEL _TIE_xt_debug_RSR_ICOUNTLEVEL\r\n#define XT_WSR_ICOUNTLEVEL _TIE_xt_debug_WSR_ICOUNTLEVEL\r\n#define XT_XSR_ICOUNTLEVEL _TIE_xt_debug_XSR_ICOUNTLEVEL\r\n#define XT_RSR_DDR _TIE_xt_debug_RSR_DDR\r\n#define XT_WSR_DDR _TIE_xt_debug_WSR_DDR\r\n#define XT_XSR_DDR _TIE_xt_debug_XSR_DDR\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_debug_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_density.h",
    "content": "/* Definitions for the xt_density TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_density_HEADER\r\n#define _XTENSA_xt_density_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern void _TIE_xt_density_ILL_N(void);\r\nextern void _TIE_xt_density_NOP_N(void);\r\nextern int _TIE_xt_density_L32I_N(const int * p, immediate i);\r\nextern void _TIE_xt_density_S32I_N(int t, int * p, immediate i);\r\nextern int _TIE_xt_density_ADD_N(int s, int t);\r\nextern int _TIE_xt_density_ADDI_N(int s, immediate i);\r\nextern int _TIE_xt_density_MOV_N(int s);\r\nextern int _TIE_xt_density_MOVI_N(immediate i);\r\n#define XT_ILL_N _TIE_xt_density_ILL_N\r\n#define XT_NOP_N _TIE_xt_density_NOP_N\r\n#define XT_L32I_N _TIE_xt_density_L32I_N\r\n#define XT_S32I_N _TIE_xt_density_S32I_N\r\n#define XT_ADD_N _TIE_xt_density_ADD_N\r\n#define XT_ADDI_N _TIE_xt_density_ADDI_N\r\n#define XT_MOV_N _TIE_xt_density_MOV_N\r\n#define XT_MOVI_N _TIE_xt_density_MOVI_N\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_density_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_exceptions.h",
    "content": "/* Definitions for the xt_exceptions TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_exceptions_HEADER\r\n#define _XTENSA_xt_exceptions_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern void _TIE_xt_exceptions_EXCW(void);\r\nextern void _TIE_xt_exceptions_SYSCALL(void);\r\nextern void _TIE_xt_exceptions_SIMCALL(void);\r\n#define XT_EXCW _TIE_xt_exceptions_EXCW\r\n#define XT_SYSCALL _TIE_xt_exceptions_SYSCALL\r\n#define XT_SIMCALL _TIE_xt_exceptions_SIMCALL\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_exceptions_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_externalregisters.h",
    "content": "/* Definitions for the xt_externalregisters TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_externalregisters_HEADER\r\n#define _XTENSA_xt_externalregisters_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern void _TIE_xt_externalregisters_RER(void);\r\nextern void _TIE_xt_externalregisters_WER(void);\r\n#define XT_RER _TIE_xt_externalregisters_RER\r\n#define XT_WER _TIE_xt_externalregisters_WER\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_externalregisters_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_interrupt.h",
    "content": "/* Definitions for the xt_interrupt TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_interrupt_HEADER\r\n#define _XTENSA_xt_interrupt_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern void _TIE_xt_interrupt_WAITI(immediate s);\r\nextern unsigned _TIE_xt_interrupt_RSR_INTERRUPT(void);\r\nextern void _TIE_xt_interrupt_WSR_INTSET(unsigned art);\r\nextern void _TIE_xt_interrupt_WSR_INTCLEAR(unsigned art);\r\nextern unsigned _TIE_xt_interrupt_RSR_INTENABLE(void);\r\nextern void _TIE_xt_interrupt_WSR_INTENABLE(unsigned art);\r\nextern void _TIE_xt_interrupt_XSR_INTENABLE(unsigned art /*inout*/);\r\n#define XT_WAITI _TIE_xt_interrupt_WAITI\r\n#define XT_RSR_INTERRUPT _TIE_xt_interrupt_RSR_INTERRUPT\r\n#define XT_WSR_INTSET _TIE_xt_interrupt_WSR_INTSET\r\n#define XT_WSR_INTCLEAR _TIE_xt_interrupt_WSR_INTCLEAR\r\n#define XT_RSR_INTENABLE _TIE_xt_interrupt_RSR_INTENABLE\r\n#define XT_WSR_INTENABLE _TIE_xt_interrupt_WSR_INTENABLE\r\n#define XT_XSR_INTENABLE _TIE_xt_interrupt_XSR_INTENABLE\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_interrupt_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_misc.h",
    "content": "/* Definitions for the xt_misc TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_misc_HEADER\r\n#define _XTENSA_xt_misc_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern int _TIE_xt_misc_NSA(int s);\r\nextern unsigned _TIE_xt_misc_NSAU(unsigned s);\r\n#define XT_NSA _TIE_xt_misc_NSA\r\n#define XT_NSAU _TIE_xt_misc_NSAU\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_misc_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_mmu.h",
    "content": "/* Definitions for the xt_mmu TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_mmu_HEADER\r\n#define _XTENSA_xt_mmu_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern void _TIE_xt_mmu_IDTLB(unsigned ars);\r\nextern unsigned _TIE_xt_mmu_RDTLB1(unsigned ars);\r\nextern unsigned _TIE_xt_mmu_RDTLB0(unsigned ars);\r\nextern unsigned _TIE_xt_mmu_PDTLB(unsigned ars);\r\nextern void _TIE_xt_mmu_WDTLB(unsigned art, unsigned ars);\r\nextern void _TIE_xt_mmu_IITLB(unsigned ars);\r\nextern unsigned _TIE_xt_mmu_RITLB1(unsigned ars);\r\nextern unsigned _TIE_xt_mmu_RITLB0(unsigned ars);\r\nextern unsigned _TIE_xt_mmu_PITLB(unsigned ars);\r\nextern void _TIE_xt_mmu_WITLB(unsigned art, unsigned ars);\r\n#define XT_IDTLB _TIE_xt_mmu_IDTLB\r\n#define XT_RDTLB1 _TIE_xt_mmu_RDTLB1\r\n#define XT_RDTLB0 _TIE_xt_mmu_RDTLB0\r\n#define XT_PDTLB _TIE_xt_mmu_PDTLB\r\n#define XT_WDTLB _TIE_xt_mmu_WDTLB\r\n#define XT_IITLB _TIE_xt_mmu_IITLB\r\n#define XT_RITLB1 _TIE_xt_mmu_RITLB1\r\n#define XT_RITLB0 _TIE_xt_mmu_RITLB0\r\n#define XT_PITLB _TIE_xt_mmu_PITLB\r\n#define XT_WITLB _TIE_xt_mmu_WITLB\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_mmu_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_mul.h",
    "content": "/* Definitions for the xt_mul TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_mul_HEADER\r\n#define _XTENSA_xt_mul_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern int _TIE_xt_mul_MUL16S(short s, short t);\r\nextern unsigned _TIE_xt_mul_MUL16U(unsigned short s, unsigned short t);\r\nextern int _TIE_xt_mul_MULL(int s, int t);\r\n#define XT_MUL16S _TIE_xt_mul_MUL16S\r\n#define XT_MUL16U _TIE_xt_mul_MUL16U\r\n#define XT_MULL _TIE_xt_mul_MULL\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_mul_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_timer.h",
    "content": "/* Definitions for the xt_timer TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_timer_HEADER\r\n#define _XTENSA_xt_timer_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern unsigned _TIE_xt_timer_RSR_CCOUNT(void);\r\nextern void _TIE_xt_timer_WSR_CCOUNT(unsigned art);\r\nextern void _TIE_xt_timer_XSR_CCOUNT(unsigned art /*inout*/);\r\nextern unsigned _TIE_xt_timer_RSR_CCOMPARE0(void);\r\nextern void _TIE_xt_timer_WSR_CCOMPARE0(unsigned art);\r\nextern void _TIE_xt_timer_XSR_CCOMPARE0(unsigned art /*inout*/);\r\n#define XT_RSR_CCOUNT _TIE_xt_timer_RSR_CCOUNT\r\n#define XT_WSR_CCOUNT _TIE_xt_timer_WSR_CCOUNT\r\n#define XT_XSR_CCOUNT _TIE_xt_timer_XSR_CCOUNT\r\n#define XT_RSR_CCOMPARE0 _TIE_xt_timer_RSR_CCOMPARE0\r\n#define XT_WSR_CCOMPARE0 _TIE_xt_timer_WSR_CCOMPARE0\r\n#define XT_XSR_CCOMPARE0 _TIE_xt_timer_XSR_CCOMPARE0\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_timer_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/tie/xt_trace.h",
    "content": "/* Definitions for the xt_trace TIE package */\r\n\r\n/*\r\n * Customer ID=7011; Build=0x2b6f6; Copyright (c) 2004 by Tensilica Inc.  ALL RIGHTS RESERVED.\r\n * These coded instructions, statements, and computer programs are the\r\n * copyrighted works and confidential proprietary information of Tensilica Inc.\r\n * They may not be modified, copied, reproduced, distributed, or disclosed to\r\n * third parties in any manner, medium, or form, in whole or in part, without\r\n * the prior written consent of Tensilica Inc.\r\n */\r\n\r\n/* Do not modify. This is automatically generated.*/\r\n\r\n#ifndef _XTENSA_xt_trace_HEADER\r\n#define _XTENSA_xt_trace_HEADER\r\n\r\n#ifdef __XTENSA__\r\n#ifdef __XCC__\r\n\r\n#include <xtensa/tie/xt_core.h>\r\n\r\n/*\r\n * The following prototypes describe intrinsic functions\r\n * corresponding to TIE instructions.  Some TIE instructions\r\n * may produce multiple results (designated as \"out\" operands\r\n * in the iclass section) or may have operands used as both\r\n * inputs and outputs (designated as \"inout\").  However, the C\r\n * and C++ languages do not provide syntax that can express\r\n * the in/out/inout constraints of TIE intrinsics.\r\n * Nevertheless, the compiler understands these constraints\r\n * and will check that the intrinsic functions are used\r\n * correctly.  To improve the readability of these prototypes,\r\n * the \"out\" and \"inout\" parameters are marked accordingly\r\n * with comments.\r\n */\r\n\r\nextern void _TIE_xt_trace_WSR_MMID(unsigned art);\r\n#define XT_WSR_MMID _TIE_xt_trace_WSR_MMID\r\n\r\n#endif /* __XCC__ */\r\n\r\n#endif /* __XTENSA__ */\r\n#endif /* !_XTENSA_xt_trace_HEADER */\r\n"
  },
  {
    "path": "app/include/xtensa/xtensa-libdb-macros.h",
    "content": "/*\r\n *  xtensa-libdb-macros.h\r\n */\r\n\r\n/* $Id: //depot/rel/Boreal/Xtensa/Software/libdb/xtensa-libdb-macros.h#2 $ */\r\n\r\n/* Copyright (c) 2004-2008 Tensilica Inc.\r\n\r\n   Permission is hereby granted, free of charge, to any person obtaining\r\n   a copy of this software and associated documentation files (the\r\n   \"Software\"), to deal in the Software without restriction, including\r\n   without limitation the rights to use, copy, modify, merge, publish,\r\n   distribute, sublicense, and/or sell copies of the Software, and to\r\n   permit persons to whom the Software is furnished to do so, subject to\r\n   the following conditions:\r\n\r\n   The above copyright notice and this permission notice shall be included\r\n   in all copies or substantial portions of the Software.\r\n\r\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */\r\n\r\n#ifndef __H_LIBDB_MACROS\r\n#define __H_LIBDB_MACROS\r\n\r\n/*\r\n *  This header file provides macros used to construct, identify and use\r\n *  \"target numbers\" that are assigned to various types of Xtensa processor\r\n *  registers and states.  These target numbers are used by GDB in the remote\r\n *  protocol, and are thus used by all GDB debugger agents (targets).\r\n *  They are also used in ELF debugger information sections (stabs, dwarf, etc).\r\n *\r\n *  These macros are separated from xtensa-libdb.h because they are needed\r\n *  by certain debugger agents that do not use or have access to libdb,\r\n *  e.g. the OCD daemon, RedBoot, XMON, etc.\r\n *\r\n *  For the time being, for compatibility with certain 3rd party debugger\r\n *  software vendors, target numbers are limited to 16 bits.  It is\r\n *  conceivable that this will be extended in the future to 32 bits.\r\n */\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n#ifndef uint32\r\n #define uint32\tunsigned int\r\n#endif\r\n#ifndef int32\r\n #define int32\tint\r\n#endif\r\n\r\n\r\n/*\r\n *  Macros to form register \"target numbers\" for various standard registers/states:\r\n */\r\n#define XTENSA_DBREGN_INVALID\t\t-1\t\t/* not a valid target number */\r\n#define XTENSA_DBREGN_A(n)\t\t(0x0000+(n))\t/* address registers a0..a15 */\r\n#define XTENSA_DBREGN_B(n)\t\t(0x0010+(n))\t/* boolean bits b0..b15 */\r\n#define XTENSA_DBREGN_PC\t\t 0x0020\t\t/* program counter */\r\n\t\t\t\t      /* 0x0021\t\t   RESERVED for use by Tensilica */\r\n#define XTENSA_DBREGN_BO(n)\t\t(0x0022+(n))\t/* boolean octuple-bits bo0..bo1 */\r\n#define XTENSA_DBREGN_BQ(n)\t\t(0x0024+(n))\t/* boolean quadruple-bits bq0..bq3 */\r\n#define XTENSA_DBREGN_BD(n)\t\t(0x0028+(n))\t/* boolean double-bits bd0..bd7 */\r\n#define XTENSA_DBREGN_F(n)\t\t(0x0030+(n))\t/* floating point registers f0..f15 */\r\n#define XTENSA_DBREGN_VEC(n)\t\t(0x0040+(n))\t/* Vectra vec regs v0..v15 */\r\n#define XTENSA_DBREGN_VSEL(n)\t\t(0x0050+(n))\t/* Vectra sel s0..s3 (V1) ..s7 (V2) */\r\n#define XTENSA_DBREGN_VALIGN(n)\t\t(0x0058+(n))\t/* Vectra valign regs u0..u3 */\r\n#define XTENSA_DBREGN_VCOEFF(n)\t\t(0x005C+(n))\t/* Vectra I vcoeff regs c0..c1 */\r\n\t\t\t\t      /* 0x005E..0x005F\t   RESERVED for use by Tensilica */\r\n#define XTENSA_DBREGN_AEP(n)\t\t(0x0060+(n))\t/* HiFi2 Audio Engine regs aep0..aep7 */\r\n#define XTENSA_DBREGN_AEQ(n)\t\t(0x0068+(n))\t/* HiFi2 Audio Engine regs aeq0..aeq3 */\r\n\t\t\t\t      /* 0x006C..0x006F\t   RESERVED for use by Tensilica */\r\n#define XTENSA_DBREGN_DF(n)\t\t(0x0070+(n))\t/* double floating point registers df0..df15 */\r\n\t\t\t\t      /* 0x0080..0x00FF\t   RESERVED for use by Tensilica */\r\n#define XTENSA_DBREGN_AR(n)\t\t(0x0100+(n))\t/* physical address regs ar0..ar63\r\n\t\t\t\t\t\t\t   (note: only with window option) */\r\n\t\t\t\t      /* 0x0140..0x01FF\t   RESERVED for use by Tensilica */\r\n#define XTENSA_DBREGN_SREG(n)\t\t(0x0200+(n))\t/* special registers 0..255 (core) */\r\n#define XTENSA_DBREGN_BR\t\tXTENSA_DBREGN_SREG(0x04)\t/* all 16 boolean bits, BR */\r\n#define XTENSA_DBREGN_MR(n)\t\tXTENSA_DBREGN_SREG(0x20+(n))\t/* MAC16 registers m0..m3 */\r\n#define XTENSA_DBREGN_UREG(n)\t\t(0x0300+(n))\t/* user registers 0..255 (TIE) */\r\n\t\t\t\t      /* 0x0400..0x0FFF\t   RESERVED for use by Tensilica */\r\n\t\t\t\t      /* 0x1000..0x1FFF\t   user-defined regfiles */\r\n\t\t\t\t      /* 0x2000..0xEFFF\t   other states (and regfiles) */\r\n#define XTENSA_DBREGN_DBAGENT(n)\t(0xF000+(n))\t/* non-processor \"registers\" 0..4095 for\r\n\t\t\t\t\t\t\t   3rd-party debugger agent defined use */\r\n\t\t\t\t      /* > 0xFFFF (32-bit) RESERVED for use by Tensilica */\r\n/*#define XTENSA_DBREGN_CONTEXT(n)\t(0x02000000+((n)<<20))*/\t/* add this macro's value to a target\r\n\t\t\t\t\t\t\t   number to identify a specific context 0..31\r\n\t\t\t\t\t\t\t   for context-replicated registers */\r\n#define XTENSA_DBREGN_MASK\t\t0xFFFF\t\t/* mask of valid target_number bits */\r\n#define XTENSA_DBREGN_WRITE_SIDE\t0x04000000\t/* flag to request write half of a register\r\n\t\t\t\t\t\t\t   split into distinct read and write entries\r\n\t\t\t\t\t\t\t   with the same target number (currently only\r\n\t\t\t\t\t\t\t   valid in a couple of libdb API functions;\r\n\t\t\t\t\t\t\t   see xtensa-libdb.h for details) */\r\n\r\n/*\r\n *  Macros to identify specific ranges of target numbers (formed above):\r\n *  NOTE:  any context number (or other upper 12 bits) are considered\r\n *  modifiers and are thus stripped out for identification purposes.\r\n */\r\n#define XTENSA_DBREGN_IS_VALID(tn)\t(((tn) & ~0xFFFF) == 0)\t/* just tests it's 16-bit unsigned */\r\n#define XTENSA_DBREGN_IS_A(tn)\t\t(((tn) & 0xFFF0)==0x0000)\t/* is a0..a15 */\r\n#define XTENSA_DBREGN_IS_B(tn)\t\t(((tn) & 0xFFF0)==0x0010)\t/* is b0..b15 */\r\n#define XTENSA_DBREGN_IS_PC(tn)\t\t(((tn) & 0xFFFF)==0x0020)\t/* is program counter */\r\n#define XTENSA_DBREGN_IS_BO(tn)\t\t(((tn) & 0xFFFE)==0x0022)\t/* is bo0..bo1 */\r\n#define XTENSA_DBREGN_IS_BQ(tn)\t\t(((tn) & 0xFFFC)==0x0024)\t/* is bq0..bq3 */\r\n#define XTENSA_DBREGN_IS_BD(tn)\t\t(((tn) & 0xFFF8)==0x0028)\t/* is bd0..bd7 */\r\n#define XTENSA_DBREGN_IS_F(tn)\t\t(((tn) & 0xFFF0)==0x0030)\t/* is f0..f15 */\r\n#define XTENSA_DBREGN_IS_VEC(tn)\t(((tn) & 0xFFF0)==0x0040)\t/* is v0..v15 */\r\n#define XTENSA_DBREGN_IS_VSEL(tn)\t(((tn) & 0xFFF8)==0x0050)\t/* is s0..s7 (s0..s3 in V1) */\r\n#define XTENSA_DBREGN_IS_VALIGN(tn)\t(((tn) & 0xFFFC)==0x0058)\t/* is u0..u3 */\r\n#define XTENSA_DBREGN_IS_VCOEFF(tn)\t(((tn) & 0xFFFE)==0x005C)\t/* is c0..c1 */\r\n#define XTENSA_DBREGN_IS_AEP(tn)\t(((tn) & 0xFFF8)==0x0060)\t/* is aep0..aep7 */\r\n#define XTENSA_DBREGN_IS_AEQ(tn)\t(((tn) & 0xFFFC)==0x0068)\t/* is aeq0..aeq3 */\r\n#define XTENSA_DBREGN_IS_DF(tn)\t\t(((tn) & 0xFFF0)==0x0070)\t/* is df0..df15 */\r\n#define XTENSA_DBREGN_IS_AR(tn)\t\t(((tn) & 0xFFC0)==0x0100)\t/* is ar0..ar63 */\r\n#define XTENSA_DBREGN_IS_SREG(tn)\t(((tn) & 0xFF00)==0x0200)\t/* is special register */\r\n#define XTENSA_DBREGN_IS_BR(tn)\t\t(((tn) & 0xFFFF)==XTENSA_DBREGN_SREG(0x04))\t/* is BR */\r\n#define XTENSA_DBREGN_IS_MR(tn)\t\t(((tn) & 0xFFFC)==XTENSA_DBREGN_SREG(0x20))\t/* m0..m3 */\r\n#define XTENSA_DBREGN_IS_UREG(tn)\t(((tn) & 0xFF00)==0x0300)\t/* is user register */\r\n#define XTENSA_DBREGN_IS_DBAGENT(tn)\t(((tn) & 0xF000)==0xF000)\t/* is non-processor */\r\n/*#define XTENSA_DBREGN_IS_CONTEXT(tn)\t(((tn) & 0x02000000) != 0)*/\t/* specifies context # */\r\n\r\n/*\r\n *  Macros to extract register index from a register \"target number\"\r\n *  when a specific range has been identified using one of the _IS_ macros above.\r\n *  These macros only return a useful value if the corresponding _IS_ macro returns true.\r\n */\r\n#define XTENSA_DBREGN_A_INDEX(tn)\t((tn) & 0x0F)\t\t/* 0..15  for a0..a15 */\r\n#define XTENSA_DBREGN_B_INDEX(tn)\t((tn) & 0x0F)\t\t/* 0..15  for b0..b15 */\r\n#define XTENSA_DBREGN_BO_INDEX(tn)\t((tn) & 0x01)\t\t/* 0..1   for bo0..bo1 */\r\n#define XTENSA_DBREGN_BQ_INDEX(tn)\t((tn) & 0x03)\t\t/* 0..3   for bq0..bq3 */\r\n#define XTENSA_DBREGN_BD_INDEX(tn)\t((tn) & 0x07)\t\t/* 0..7   for bd0..bd7 */\r\n#define XTENSA_DBREGN_F_INDEX(tn)\t((tn) & 0x0F)\t\t/* 0..15  for f0..f15 */\r\n#define XTENSA_DBREGN_VEC_INDEX(tn)\t((tn) & 0x0F)\t\t/* 0..15  for v0..v15 */\r\n#define XTENSA_DBREGN_VSEL_INDEX(tn)\t((tn) & 0x07)\t\t/* 0..7   for s0..s7 */\r\n#define XTENSA_DBREGN_VALIGN_INDEX(tn)\t((tn) & 0x03)\t\t/* 0..3   for u0..u3 */\r\n#define XTENSA_DBREGN_VCOEFF_INDEX(tn)\t((tn) & 0x01)\t\t/* 0..1   for c0..c1 */\r\n#define XTENSA_DBREGN_AEP_INDEX(tn)\t((tn) & 0x07)\t\t/* 0..7   for aep0..aep7 */\r\n#define XTENSA_DBREGN_AEQ_INDEX(tn)\t((tn) & 0x03)\t\t/* 0..3   for aeq0..aeq3 */\r\n#define XTENSA_DBREGN_DF_INDEX(tn)\t((tn) & 0x0F)\t\t/* 0..15  for df0..df15 */\r\n#define XTENSA_DBREGN_AR_INDEX(tn)\t((tn) & 0x3F)\t\t/* 0..63  for ar0..ar63 */\r\n#define XTENSA_DBREGN_SREG_INDEX(tn)\t((tn) & 0xFF)\t\t/* 0..255 for special registers */\r\n#define XTENSA_DBREGN_MR_INDEX(tn)\t((tn) & 0x03)\t\t/* 0..3   for m0..m3 */\r\n#define XTENSA_DBREGN_UREG_INDEX(tn)\t((tn) & 0xFF)\t\t/* 0..255 for user registers */\r\n#define XTENSA_DBREGN_DBAGENT_INDEX(tn)\t((tn) & 0xFFF)\t\t/* 0..4095 for non-processor */\r\n/*#define XTENSA_DBREGN_CONTEXT_INDEX(tn)\t(((tn) >> 20) & 0x1F)*/\t/* 0..31  context numbers */\r\n\r\n\r\n\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n      \r\n#endif /* __H_LIBDB_MACROS */\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/xtensa-xer.h",
    "content": "/* xer-constants.h -- various constants describing external registers accessed \r\n      via wer and rer.\r\n\r\n      TODO: find a better prefix. Also conditionalize certain constants based\r\n      on number of cores and interrupts actually present.  \r\n*/\r\n\r\n/*\r\n * Copyright (c) 1999-2008 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#include <xtensa/config/core.h>\r\n\r\n#define NUM_INTERRUPTS 27\r\n#define NUM_CORES       4\r\n\r\n/* Routing of NMI (BInterrupt2)\tand interrupts 0..n-1 (BInterrupt3+) \r\n   RER reads\r\n   WER writes\r\n */\r\n\r\n#define XER_MIROUT           0x0000\r\n#define XER_MIROUT_LAST      (XER_MIROUT + NUM_INTERRUPTS)\r\n\r\n\r\n/* IPI to core M (all 16 causes). \r\n   \r\n   RER reads\r\n   WER clears\r\n */\r\n#define XER_MIPICAUSE        0x0100\r\n#define XER_MIPICAUSE_FIELD_A_FIRST 0x0\r\n#define XER_MIPICAUSE_FIELD_A_LAST  0x0\r\n#define XER_MIPICAUSE_FIELD_B_FIRST 0x1\r\n#define XER_MIPICAUSE_FIELD_B_LAST  0x3\r\n#define XER_MIPICAUSE_FIELD_C_FIRST 0x4\r\n#define XER_MIPICAUSE_FIELD_C_LAST  0x7\r\n#define XER_MIPICAUSE_FIELD_D_FIRST 0x8\r\n#define XER_MIPICAUSE_FIELD_D_LAST  0xF\r\n\r\n\r\n/* IPI from cause bit 0..15  \r\n\r\n   RER invalid\r\n   WER sets\r\n*/\r\n#define XER_MIPISET          0x0140\r\n#define XER_MIPISET_LAST     0x014F\r\n\r\n\r\n/* Global enable\r\n\r\n   RER read\r\n   WER clear\r\n*/\r\n#define XER_MIENG            0x0180\r\n\r\n\r\n/* Global enable\r\n\r\n   RER invalid\r\n   WER set\r\n*/\r\n#define XER_MIENG_SET        0x0184\r\n\r\n/* Global assert\r\n\r\n   RER read\r\n   WER clear\r\n*/\r\n#define XER_MIASG            0x0188\r\n\r\n\r\n/* Global enable\r\n\r\n   RER invalid\r\n   WER set\r\n*/\r\n#define XER_MIASG_SET        0x018C\r\n\r\n\r\n/* IPI partition register\r\n\r\n   RER read\r\n   WER write\r\n*/\r\n#define XER_PART            0x0190\r\n#define XER_IPI0            0x0\r\n#define XER_IPI1            0x1\r\n#define XER_IPI2            0x2\r\n#define XER_IPI3            0x3\r\n\r\n#define XER_PART_ROUTE_IPI(NUM, FIELD) ((NUM) << ((FIELD) << 2))\r\n\r\n#define XER_PART_ROUTE_IPI_CAUSE(TO_A, TO_B, TO_C, TO_D)\t\t\\\r\n  (XER_PART_ROUTE_IPI(TO_A, XER_IPI0) |\t\t\t\t\t\\\r\n   XER_PART_ROUTE_IPI(TO_B, XER_IPI1) |\t\t\t\t\t\\\r\n   XER_PART_ROUTE_IPI(TO_C, XER_IPI2) |\t\t\t\t\t\\\r\n   XER_PART_ROUTE_IPI(TO_D, XER_IPI3))\r\n\r\n#define XER_IPI_WAKE_EXT_INTERRUPT XCHAL_EXTINT0_NUM\r\n#define XER_IPI_WAKE_CAUSE  XER_MIPICAUSE_FIELD_C_FIRST\r\n#define XER_IPI_WAKE_ADDRESS    (XER_MIPISET + XER_IPI_WAKE_CAUSE)\r\n#define XER_DEFAULT_IPI_ROUTING XER_PART_ROUTE_IPI_CAUSE(XER_IPI1, XER_IPI0, XER_IPI2, XER_IPI3)\r\n\r\n\r\n/* System configuration ID\r\n\r\n   RER read\r\n   WER invalid\r\n*/\r\n#define XER_SYSCFGID        0x01A0\r\n\r\n\r\n/* RunStall to slave processors\r\n\r\n   RER read\r\n   WER write\r\n*/\r\n#define XER_MPSCORE        0x0200\r\n\r\n\r\n/* Cache coherency ON\r\n\r\n   RER read\r\n   WER write\r\n*/\r\n#define XER_CCON           0x0220\r\n\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/xtruntime-frames.h",
    "content": "/*  xtruntime-frames.h  -  exception stack frames for single-threaded run-time  */\r\n/* $Id: //depot/rel/Boreal/Xtensa/OS/include/xtensa/xtruntime-frames.h#2 $ */\r\n\r\n/*\r\n * Copyright (c) 2002-2007 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef _XTRUNTIME_FRAMES_H_\r\n#define _XTRUNTIME_FRAMES_H_\r\n\r\n#include <xtensa/config/core.h>\r\n\r\n/*  Macros that help define structures for both C and assembler:  */\r\n#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)\r\n#define STRUCT_BEGIN\t\t.pushsection .text; .struct 0\r\n#define STRUCT_FIELD(ctype,size,pre,name)\tpre##name:\t.space\tsize\r\n#define STRUCT_AFIELD(ctype,size,pre,name,n)\tpre##name:\t.space\t(size)*(n)\r\n#define STRUCT_END(sname)\tsname##Size:; .popsection\r\n#else /*_ASMLANGUAGE||__ASSEMBLER__*/\r\n#define STRUCT_BEGIN\t\ttypedef struct {\r\n#define STRUCT_FIELD(ctype,size,pre,name)\tctype\tname;\r\n#define STRUCT_AFIELD(ctype,size,pre,name,n)\tctype\tname[n];\r\n#define STRUCT_END(sname)\t} sname;\r\n#endif /*_ASMLANGUAGE||__ASSEMBLER__*/\r\n\r\n\r\n/*\r\n *  Kernel vector mode exception stack frame.\r\n *\r\n *  NOTE:  due to the limited range of addi used in the current\r\n *  kernel exception vector, and the fact that historically\r\n *  the vector is limited to 12 bytes, the size of this\r\n *  stack frame is limited to 128 bytes (currently at 64).\r\n */\r\nSTRUCT_BEGIN\r\nSTRUCT_FIELD (long,4,KEXC_,pc)\t\t/* \"parm\" */\r\nSTRUCT_FIELD (long,4,KEXC_,ps)\r\nSTRUCT_AFIELD(long,4,KEXC_,areg, 4)\t/* a12 .. a15 */\r\nSTRUCT_FIELD (long,4,KEXC_,sar)\t\t/* \"save\" */\r\n#if XCHAL_HAVE_LOOPS\r\nSTRUCT_FIELD (long,4,KEXC_,lcount)\r\nSTRUCT_FIELD (long,4,KEXC_,lbeg)\r\nSTRUCT_FIELD (long,4,KEXC_,lend)\r\n#endif\r\n#if XCHAL_HAVE_MAC16\r\nSTRUCT_FIELD (long,4,KEXC_,acclo)\r\nSTRUCT_FIELD (long,4,KEXC_,acchi)\r\nSTRUCT_AFIELD(long,4,KEXC_,mr, 4)\r\n#endif\r\nSTRUCT_END(KernelFrame)\r\n\r\n\r\n/*\r\n *  User vector mode exception stack frame:\r\n *\r\n *  WARNING:  if you modify this structure, you MUST modify the\r\n *  computation of the pad size (ALIGNPAD) accordingly.\r\n */\r\nSTRUCT_BEGIN\r\nSTRUCT_FIELD (long,4,UEXC_,pc)\r\nSTRUCT_FIELD (long,4,UEXC_,ps)\r\nSTRUCT_FIELD (long,4,UEXC_,sar)\r\nSTRUCT_FIELD (long,4,UEXC_,vpri)\r\n#ifdef __XTENSA_CALL0_ABI__\r\nSTRUCT_FIELD (long,4,UEXC_,a0)\r\n#endif\r\nSTRUCT_FIELD (long,4,UEXC_,a2)\r\nSTRUCT_FIELD (long,4,UEXC_,a3)\r\nSTRUCT_FIELD (long,4,UEXC_,a4)\r\nSTRUCT_FIELD (long,4,UEXC_,a5)\r\n#ifdef __XTENSA_CALL0_ABI__\r\nSTRUCT_FIELD (long,4,UEXC_,a6)\r\nSTRUCT_FIELD (long,4,UEXC_,a7)\r\nSTRUCT_FIELD (long,4,UEXC_,a8)\r\nSTRUCT_FIELD (long,4,UEXC_,a9)\r\nSTRUCT_FIELD (long,4,UEXC_,a10)\r\nSTRUCT_FIELD (long,4,UEXC_,a11)\r\nSTRUCT_FIELD (long,4,UEXC_,a12)\r\nSTRUCT_FIELD (long,4,UEXC_,a13)\r\nSTRUCT_FIELD (long,4,UEXC_,a14)\r\nSTRUCT_FIELD (long,4,UEXC_,a15)\r\n#endif\r\nSTRUCT_FIELD (long,4,UEXC_,exccause)\t/* NOTE: can probably rid of this one (pass direct) */\r\n#if XCHAL_HAVE_LOOPS\r\nSTRUCT_FIELD (long,4,UEXC_,lcount)\r\nSTRUCT_FIELD (long,4,UEXC_,lbeg)\r\nSTRUCT_FIELD (long,4,UEXC_,lend)\r\n#endif\r\n#if XCHAL_HAVE_MAC16\r\nSTRUCT_FIELD (long,4,UEXC_,acclo)\r\nSTRUCT_FIELD (long,4,UEXC_,acchi)\r\nSTRUCT_AFIELD(long,4,UEXC_,mr, 4)\r\n#endif\r\n/* ALIGNPAD is the 16-byte alignment padding. */\r\n#ifdef __XTENSA_CALL0_ABI__\r\n# define CALL0_ABI\t1\r\n#else\r\n# define CALL0_ABI\t0\r\n#endif\r\n#define ALIGNPAD  ((3 + XCHAL_HAVE_LOOPS*1 + XCHAL_HAVE_MAC16*2 + CALL0_ABI*1) & 3)\r\n#if ALIGNPAD\r\nSTRUCT_AFIELD(long,4,UEXC_,pad, ALIGNPAD)\t/* 16-byte alignment padding */\r\n#endif\r\n/*STRUCT_AFIELD(char,1,UEXC_,ureg, (XCHAL_CPEXTRA_SA_SIZE_TOR2+3)&-4)*/\t/* not used, and doesn't take alignment into account */\r\nSTRUCT_END(UserFrame)\r\n\r\n\r\n#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)\r\n\r\n\r\n/*  Check for UserFrameSize small enough not to require rounding...:  */\r\n\t/*  Skip 16-byte save area, then 32-byte space for 8 regs of call12\r\n\t *  (which overlaps with 16-byte GCC nested func chaining area),\r\n\t *  then exception stack frame:  */\r\n\t.set\tUserFrameTotalSize, 16+32+UserFrameSize\r\n\t/*  Greater than 112 bytes? (max range of ADDI, both signs, when aligned to 16 bytes):  */\r\n\t.ifgt\tUserFrameTotalSize-112\r\n\t/*  Round up to 256-byte multiple to accelerate immediate adds:  */\r\n\t.set\tUserFrameTotalSize, ((UserFrameTotalSize+255) & 0xFFFFFF00)\r\n\t.endif\r\n# define ESF_TOTALSIZE\tUserFrameTotalSize\r\n\r\n#endif /* _ASMLANGUAGE || __ASSEMBLER__ */\r\n\r\n\r\n#if XCHAL_NUM_CONTEXTS > 1\r\n/*  Structure of info stored on new context's stack for setup:  */\r\nSTRUCT_BEGIN\r\nSTRUCT_FIELD (long,4,INFO_,sp)\r\nSTRUCT_FIELD (long,4,INFO_,arg1)\r\nSTRUCT_FIELD (long,4,INFO_,funcpc)\r\nSTRUCT_FIELD (long,4,INFO_,prevps)\r\nSTRUCT_END(SetupInfo)\r\n#endif\r\n\r\n\r\n#define KERNELSTACKSIZE\t1024\r\n\r\n\r\n#endif /* _XTRUNTIME_FRAMES_H_ */\r\n\r\n"
  },
  {
    "path": "app/include/xtensa/xtruntime.h",
    "content": "/*\r\n * xtruntime.h  --  general C definitions for single-threaded run-time\r\n *\r\n * Copyright (c) 2002-2008 Tensilica Inc.\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining\r\n * a copy of this software and associated documentation files (the\r\n * \"Software\"), to deal in the Software without restriction, including\r\n * without limitation the rights to use, copy, modify, merge, publish,\r\n * distribute, sublicense, and/or sell copies of the Software, and to\r\n * permit persons to whom the Software is furnished to do so, subject to\r\n * the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included\r\n * in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\r\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef XTRUNTIME_H\r\n#define XTRUNTIME_H\r\n\r\n#include <xtensa/config/core.h>\r\n#include <xtensa/config/specreg.h>\r\n\r\n#ifndef XTSTR\r\n#define _XTSTR(x)\t# x\r\n#define XTSTR(x)\t_XTSTR(x)\r\n#endif\r\n\r\n#define _xtos_set_execption_handler _xtos_set_exception_handler\t/* backward compatibility */\r\n#define _xtos_set_saved_intenable\t_xtos_ints_on\t/* backward compatibility */\r\n#define _xtos_clear_saved_intenable\t_xtos_ints_off\t/* backward compatibility */\r\n\r\n#if !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__)\r\n\r\n#ifdef __cplusplus\r\nextern \"C\" {\r\n#endif\r\n\r\n/*typedef void (_xtos_timerdelta_func)(int);*/\r\n#ifdef __cplusplus\r\ntypedef void (_xtos_handler_func)(...);\r\n#else\r\ntypedef void (_xtos_handler_func)();\r\n#endif\r\ntypedef _xtos_handler_func *_xtos_handler;\r\n\r\n/*\r\n *  unsigned XTOS_SET_INTLEVEL(int intlevel);\r\n *  This macro sets the current interrupt level.\r\n *  The 'intlevel' parameter must be a constant.\r\n *  This macro returns a 32-bit value that must be passed to\r\n *  XTOS_RESTORE_INTLEVEL() to restore the previous interrupt level.\r\n *  XTOS_RESTORE_JUST_INTLEVEL() also does this, but in XEA2 configs\r\n *  it restores only PS.INTLEVEL rather than the entire PS register\r\n *  and thus is slower.\r\n */\r\n#if !XCHAL_HAVE_INTERRUPTS\r\n# define XTOS_SET_INTLEVEL(intlevel)\t\t0\r\n# define XTOS_SET_MIN_INTLEVEL(intlevel)\t0\r\n# define XTOS_RESTORE_INTLEVEL(restoreval)\r\n# define XTOS_RESTORE_JUST_INTLEVEL(restoreval)\r\n#elif XCHAL_HAVE_XEA2\r\n/*  In XEA2, we can simply safely set PS.INTLEVEL directly:  */\r\n/*  NOTE: these asm macros don't modify memory, but they are marked\r\n *  as such to act as memory access barriers to the compiler because\r\n *  these macros are sometimes used to delineate critical sections;\r\n *  function calls are natural barriers (the compiler does not know\r\n *  whether a function modifies memory) unless declared to be inlined.  */\r\n# define XTOS_SET_INTLEVEL(intlevel)\t\t({ unsigned __tmp; \\\r\n\t\t\t__asm__ __volatile__(\t\"rsil\t%0, \" XTSTR(intlevel) \"\\n\" \\\r\n\t\t\t\t\t\t: \"=a\" (__tmp) : : \"memory\" ); \\\r\n\t\t\t__tmp;})\r\n# define XTOS_SET_MIN_INTLEVEL(intlevel)\t\t({ unsigned __tmp, __tmp2, __tmp3; \\\r\n\t\t\t__asm__ __volatile__(\t\"rsr\t%0, \" XTSTR(PS) \"\\n\"\t/* get old (current) PS.INTLEVEL */ \\\r\n\t\t\t\t\t\t\"movi\t%2, \" XTSTR(intlevel) \"\\n\" \\\r\n\t\t\t\t\t\t\"extui\t%1, %0, 0, 4\\n\"\t/* keep only INTLEVEL bits of parameter */ \\\r\n\t\t\t\t\t\t\"blt\t%2, %1, 1f\\n\" \\\r\n\t\t\t\t\t\t\"rsil\t%0, \" XTSTR(intlevel) \"\\n\" \\\r\n\t\t\t\t\t\t\"1:\\n\" \\\r\n\t\t\t\t\t\t: \"=a\" (__tmp), \"=&a\" (__tmp2), \"=&a\" (__tmp3) : : \"memory\" ); \\\r\n\t\t\t__tmp;})\r\n# define XTOS_RESTORE_INTLEVEL(restoreval)\tdo{ unsigned __tmp = (restoreval); \\\r\n\t\t\t__asm__ __volatile__(\t\"wsr\t%0, \" XTSTR(PS) \" ; rsync\\n\" \\\r\n\t\t\t\t\t\t: : \"a\" (__tmp) : \"memory\" ); \\\r\n\t\t\t}while(0)\r\n# define XTOS_RESTORE_JUST_INTLEVEL(restoreval)\t_xtos_set_intlevel(restoreval)\r\n#else\r\n/*  In XEA1, we have to rely on INTENABLE register virtualization:  */\r\nextern unsigned\t\t_xtos_set_vpri( unsigned vpri );\r\nextern unsigned\t\t_xtos_vpri_enabled;\t/* current virtual priority */\r\n# define XTOS_SET_INTLEVEL(intlevel)\t\t_xtos_set_vpri(~XCHAL_INTLEVEL_ANDBELOW_MASK(intlevel))\r\n# define XTOS_SET_MIN_INTLEVEL(intlevel)\t_xtos_set_vpri(_xtos_vpri_enabled & ~XCHAL_INTLEVEL_ANDBELOW_MASK(intlevel))\r\n# define XTOS_RESTORE_INTLEVEL(restoreval)\t_xtos_set_vpri(restoreval)\r\n# define XTOS_RESTORE_JUST_INTLEVEL(restoreval)\t_xtos_set_vpri(restoreval)\r\n#endif\r\n\r\n/*\r\n *  The following macros build upon the above.  They are generally used\r\n *  instead of invoking the SET_INTLEVEL and SET_MIN_INTLEVEL macros directly.\r\n *  They all return a value that can be used with XTOS_RESTORE_INTLEVEL()\r\n *  or _xtos_restore_intlevel() or _xtos_restore_just_intlevel() to restore\r\n *  the effective interrupt level to what it was before the macro was invoked.\r\n *  In XEA2, the DISABLE macros are much faster than the MASK macros\r\n *  (in all configs, DISABLE sets the effective interrupt level, whereas MASK\r\n *  makes ensures the effective interrupt level is at least the level given\r\n *  without lowering it; in XEA2 with INTENABLE virtualization, these macros\r\n *  affect PS.INTLEVEL only, not the virtual priority, so DISABLE has partial\r\n *  MASK semantics).\r\n *\r\n *  A typical critical section sequence might be:\r\n *\tunsigned rval = XTOS_DISABLE_EXCM_INTERRUPTS;\r\n *\t... critical section ...\r\n *\tXTOS_RESTORE_INTLEVEL(rval);\r\n */\r\n/*  Enable all interrupts (those activated with _xtos_ints_on()):  */\r\n#define XTOS_ENABLE_INTERRUPTS\t\tXTOS_SET_INTLEVEL(0)\r\n/*  Disable low priority level interrupts (they can interact with the OS):  */\r\n#define XTOS_DISABLE_LOWPRI_INTERRUPTS\tXTOS_SET_INTLEVEL(XCHAL_NUM_LOWPRI_LEVELS)\r\n#define XTOS_MASK_LOWPRI_INTERRUPTS\tXTOS_SET_MIN_INTLEVEL(XCHAL_NUM_LOWPRI_LEVELS)\r\n/*  Disable interrupts that can interact with the OS:  */\r\n#define XTOS_DISABLE_EXCM_INTERRUPTS\tXTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL)\r\n#define XTOS_MASK_EXCM_INTERRUPTS\tXTOS_SET_MIN_INTLEVEL(XCHAL_EXCM_LEVEL)\r\n#if 0 /* XTOS_LOCK_LEVEL is not exported to applications */\r\n/*  Disable interrupts that can interact with the OS, or manipulate virtual INTENABLE:  */\r\n#define XTOS_DISABLE_LOCK_INTERRUPTS\tXTOS_SET_INTLEVEL(XTOS_LOCK_LEVEL)\r\n#define XTOS_MASK_LOCK_INTERRUPTS\tXTOS_SET_MIN_INTLEVEL(XTOS_LOCK_LEVEL)\r\n#endif\r\n/*  Disable ALL interrupts (not for common use, particularly if one's processor\r\n *  configuration has high-level interrupts and one cares about their latency):  */\r\n#define XTOS_DISABLE_ALL_INTERRUPTS\tXTOS_SET_INTLEVEL(15)\r\n\r\n\r\nextern unsigned int\t_xtos_ints_off( unsigned int mask );\r\nextern unsigned int\t_xtos_ints_on( unsigned int mask );\r\nextern unsigned\t\t_xtos_set_intlevel( int intlevel );\r\nextern unsigned\t\t_xtos_set_min_intlevel( int intlevel );\r\nextern unsigned\t\t_xtos_restore_intlevel( unsigned restoreval );\r\nextern unsigned\t\t_xtos_restore_just_intlevel( unsigned restoreval );\r\nextern _xtos_handler\t_xtos_set_interrupt_handler( int n, _xtos_handler f );\r\nextern _xtos_handler\t_xtos_set_interrupt_handler_arg( int n, _xtos_handler f, void *arg );\r\nextern _xtos_handler\t_xtos_set_exception_handler( int n, _xtos_handler f );\r\n\r\nextern void\t\t_xtos_memep_initrams( void );\r\nextern void\t\t_xtos_memep_enable( int flags );\r\n\r\n/*  Deprecated (but kept because they were documented):  */\r\nextern unsigned int\t_xtos_read_ints( void );\t\t/* use xthal_get_interrupt() instead */\r\nextern void\t\t_xtos_clear_ints( unsigned int mask );\t/* use xthal_set_intclear() instead */\r\n\r\n#if XCHAL_NUM_CONTEXTS > 1\r\nextern unsigned\t\t_xtos_init_context(int context_num, int stack_size,\r\n\t\t\t\t\t    _xtos_handler_func *start_func, int arg1);\r\n#endif\r\n\r\n/*  Deprecated:  */\r\n#if XCHAL_NUM_TIMERS > 0\r\nextern void\t\t_xtos_timer_0_delta( int cycles );\r\n#endif\r\n#if XCHAL_NUM_TIMERS > 1\r\nextern void\t\t_xtos_timer_1_delta( int cycles );\r\n#endif\r\n#if XCHAL_NUM_TIMERS > 2\r\nextern void\t\t_xtos_timer_2_delta( int cycles );\r\n#endif\r\n#if XCHAL_NUM_TIMERS > 3\r\nextern void\t\t_xtos_timer_3_delta( int cycles );\r\n#endif\r\n\r\n#ifdef __cplusplus\r\n}\r\n#endif\r\n\r\n#endif /* !_ASMLANGUAGE && !__ASSEMBLER__ */\r\n\r\n#endif /* XTRUNTIME_H */\r\n\r\n"
  },
  {
    "path": "app/json/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\n\nGEN_LIBS = libjson.a\n\nendif\n\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../libc\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/json/cJson.c",
    "content": "/*\n  Copyright (c) 2009 Dave Gamble\n\n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files (the \"Software\"), to deal\n  in the Software without restriction, including without limitation the rights\n  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  copies of the Software, and to permit persons to whom the Software is\n  furnished to do so, subject to the following conditions:\n\n  The above copyright notice and this permission notice shall be included in\n  all copies or substantial portions of the Software.\n\n  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n  THE SOFTWARE.\n*/\n\n/* cJSON */\n/* JSON parser in C. */\n#include <math.h>\n#include <float.h>\n#include <limits.h>\n#include <ctype.h>\n\n#include \"user_interface.h\"\n#include \"mem.h\"\n\n#include \"json/cJson.h\"\n\nstatic const char *ep;\n\n#ifndef cJSON_malloc\n#define cJSON_malloc os_malloc\n#endif\n\n#ifndef cJSON_free\n#define cJSON_free os_free\n#endif\n\n#ifndef cJSON_strchr\n#define cJSON_strchr os_strchr\n#endif\n\n#ifndef sprintf\n#define sprintf os_sprintf\n#endif\n\nconst char *ICACHE_FLASH_ATTR\ncJSON_GetErrorPtr(void)\n{\n    return ep;\n}\n\nstatic int ICACHE_FLASH_ATTR\ncJSON_strcasecmp(const char *s1, const char *s2)\n{\n    if (!s1) {\n        return (s1 == s2) ? 0 : 1;\n    }\n\n    if (!s2) {\n        return 1;\n    }\n\n    for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) if (*s1 == 0) {\n            return 0;\n        }\n\n    return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);\n}\n\nstatic char *ICACHE_FLASH_ATTR\ncJSON_strdup(const char *str)\n{\n    size_t len;\n    char *copy;\n\n    len = strlen(str) + 1;\n\n    if (!(copy = (char *)cJSON_malloc(len))) {\n        return 0;\n    }\n\n    memcpy(copy, str, len);\n    return copy;\n}\n\n/* Internal constructor. */\nstatic cJSON *ICACHE_FLASH_ATTR\ncJSON_New_Item(void)\n{\n    cJSON *node = (cJSON *)cJSON_malloc(sizeof(cJSON));\n\n    if (node) {\n        memset(node, 0, sizeof(cJSON));\n    }\n\n    return node;\n}\n\n/* Delete a cJSON structure. */\nvoid ICACHE_FLASH_ATTR\ncJSON_Delete(cJSON *c)\n{\n    cJSON *next;\n\n    while (c) {\n        next = c->next;\n\n        if (!(c->type & cJSON_IsReference) && c->child) {\n            cJSON_Delete(c->child);\n        }\n\n        if (!(c->type & cJSON_IsReference) && c->valuestring) {\n            cJSON_free(c->valuestring);\n        }\n\n        if (c->string) {\n            cJSON_free(c->string);\n        }\n\n        cJSON_free(c);\n        c = next;\n    }\n}\n\n/* Parse the input text to generate a number, and populate the result into item. */\nstatic const char *ICACHE_FLASH_ATTR\nparse_number(cJSON *item, const char *num)\n{\n    double n = 0, sign = 1, scale = 0;\n    int subscale = 0, signsubscale = 1;\n\n    if (*num == '-') {\n        sign = -1, num++;    /* Has sign? */\n    }\n\n    if (*num == '0') {\n        num++;    /* is zero */\n    }\n\n    if (*num >= '1' && *num <= '9') do {\n            n = (n * 10.0) + (*num++ -'0');\n        }   while (*num >= '0' && *num <= '9'); /* Number? */\n\n    if (*num == '.' && num[1] >= '0' && num[1] <= '9') {\n        num++;           /* Fractional part? */\n\n        do {\n            n = (n * 10.0) + (*num++ -'0'), scale--;\n        } while (*num >= '0' && *num <= '9');\n    }\n\n    if (*num == 'e' || *num == 'E') { /* Exponent? */\n        num++;\n\n        if (*num == '+') {\n            num++;\n        } else if (*num == '-') {\n            signsubscale = -1, num++;    /* With sign? */\n        }\n\n        while (*num >= '0' && *num <= '9') {\n            subscale = (subscale * 10) + (*num++ - '0');    /* Number? */\n        }\n    }\n\n//    n = sign * n * pow(10.0, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */\n\n    item->valuedouble = n;\n    item->valueint = (int)n;\n    item->type = cJSON_Number;\n    return num;\n}\n\n/* Render the number nicely from the given item into a string. */\nstatic char *ICACHE_FLASH_ATTR\nprint_number(cJSON *item)\n{\n    char *str;\n    double d = item->valuedouble;\n\n    if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {\n        str = (char *)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */\n\n        if (str) {\n        \tsprintf(str, \"%d\", item->valueint);\n        }\n    } else {\n        str = (char *)cJSON_malloc(64); /* This is a nice tradeoff. */\n\n        if (str) {\n            //if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60) {\n            sprintf(str, \"%f\", d);\n        }\n    }\n\n    return str;\n}\n\nstatic unsigned ICACHE_FLASH_ATTR\nparse_hex4(const char *str)\n{\n    unsigned h = 0;\n\n    if (*str >= '0' && *str <= '9') {\n        h += (*str) - '0';\n    } else if (*str >= 'A' && *str <= 'F') {\n        h += 10 + (*str) - 'A';\n    } else if (*str >= 'a' && *str <= 'f') {\n        h += 10 + (*str) - 'a';\n    } else {\n        return 0;\n    }\n\n    h = h << 4;\n    str++;\n\n    if (*str >= '0' && *str <= '9') {\n        h += (*str) - '0';\n    } else if (*str >= 'A' && *str <= 'F') {\n        h += 10 + (*str) - 'A';\n    } else if (*str >= 'a' && *str <= 'f') {\n        h += 10 + (*str) - 'a';\n    } else {\n        return 0;\n    }\n\n    h = h << 4;\n    str++;\n\n    if (*str >= '0' && *str <= '9') {\n        h += (*str) - '0';\n    } else if (*str >= 'A' && *str <= 'F') {\n        h += 10 + (*str) - 'A';\n    } else if (*str >= 'a' && *str <= 'f') {\n        h += 10 + (*str) - 'a';\n    } else {\n        return 0;\n    }\n\n    h = h << 4;\n    str++;\n\n    if (*str >= '0' && *str <= '9') {\n        h += (*str) - '0';\n    } else if (*str >= 'A' && *str <= 'F') {\n        h += 10 + (*str) - 'A';\n    } else if (*str >= 'a' && *str <= 'f') {\n        h += 10 + (*str) - 'a';\n    } else {\n        return 0;\n    }\n\n    return h;\n}\n\n/* Parse the input text into an unescaped cstring, and populate item. */\nstatic const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };\nstatic const char *ICACHE_FLASH_ATTR\nparse_string(cJSON *item, const char *str)\n{\n    const char *ptr = str + 1;\n    char *ptr2;\n    char *out;\n    int len = 0;\n    unsigned uc, uc2;\n\n    if (*str != '\\\"') {\n        ep = str;    /* not a string! */\n        return 0;\n    }\n\n    while (*ptr != '\\\"' && *ptr && ++len) if (*ptr++ == '\\\\') {\n            ptr++;    /* Skip escaped quotes. */\n        }\n\n    out = (char *)cJSON_malloc(len + 1); /* This is how long we need for the string, roughly. */\n\n    if (!out) {\n        return 0;\n    }\n\n    ptr = str + 1;\n    ptr2 = out;\n\n    while (*ptr != '\\\"' && *ptr) {\n        if (*ptr != '\\\\') {\n            *ptr2++ = *ptr++;\n        } else {\n            ptr++;\n\n            switch (*ptr) {\n                case 'b':\n                    *ptr2++ = '\\b';\n                    break;\n\n                case 'f':\n                    *ptr2++ = '\\f';\n                    break;\n\n                case 'n':\n                    *ptr2++ = '\\n';\n                    break;\n\n                case 'r':\n                    *ptr2++ = '\\r';\n                    break;\n\n                case 't':\n                    *ptr2++ = '\\t';\n                    break;\n\n                case 'u':    /* transcode utf16 to utf8. */\n                    uc = parse_hex4(ptr + 1);\n                    ptr += 4;  /* get the unicode char. */\n\n                    if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) {\n                        break;    /* check for invalid. */\n                    }\n\n                    if (uc >= 0xD800 && uc <= 0xDBFF) { /* UTF16 surrogate pairs.   */\n                        if (ptr[1] != '\\\\' || ptr[2] != 'u') {\n                            break;    /* missing second-half of surrogate.  */\n                        }\n\n                        uc2 = parse_hex4(ptr + 3);\n                        ptr += 6;\n\n                        if (uc2 < 0xDC00 || uc2 > 0xDFFF) {\n                            break;    /* invalid second-half of surrogate.  */\n                        }\n\n                        uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));\n                    }\n\n                    len = 4;\n\n                    if (uc < 0x80) {\n                        len = 1;\n                    } else if (uc < 0x800) {\n                        len = 2;\n                    } else if (uc < 0x10000) {\n                        len = 3;\n                    }\n\n                    ptr2 += len;\n\n                    switch (len) {\n                        case 4:\n                            *--ptr2 = ((uc | 0x80) & 0xBF);\n                            uc >>= 6;\n\n                        case 3:\n                            *--ptr2 = ((uc | 0x80) & 0xBF);\n                            uc >>= 6;\n\n                        case 2:\n                            *--ptr2 = ((uc | 0x80) & 0xBF);\n                            uc >>= 6;\n\n                        case 1:\n                            *--ptr2 = (uc | firstByteMark[len]);\n                    }\n\n                    ptr2 += len;\n                    break;\n\n                default:\n                    *ptr2++ = *ptr;\n                    break;\n            }\n\n            ptr++;\n        }\n    }\n\n    *ptr2 = 0;\n\n    if (*ptr == '\\\"') {\n        ptr++;\n    }\n\n    item->valuestring = out;\n    item->type = cJSON_String;\n    return ptr;\n}\n\n/* Render the cstring provided to an escaped version that can be printed. */\nstatic char *ICACHE_FLASH_ATTR\nprint_string_ptr(const char *str)\n{\n    const char *ptr;\n    char *ptr2, *out;\n    int len = 0;\n    unsigned char token;\n\n    if (!str) {\n        return cJSON_strdup(\"\");\n    }\n\n    ptr = str;\n\n    while ((token = *ptr) && ++len) {\n        if (cJSON_strchr(\"\\\"\\\\\\b\\f\\n\\r\\t\", token)) {\n            len++;\n        } else if (token < 32) {\n            len += 5;\n        }\n\n        ptr++;\n    }\n\n    out = (char *)cJSON_malloc(len + 3);\n\n    if (!out) {\n        return 0;\n    }\n\n    ptr2 = out;\n    ptr = str;\n    *ptr2++ = '\\\"';\n\n    while (*ptr) {\n        if ((unsigned char)*ptr > 31 && *ptr != '\\\"' && *ptr != '\\\\') {\n            *ptr2++ = *ptr++;\n        } else {\n            *ptr2++ = '\\\\';\n\n            switch (token = *ptr++) {\n                case '\\\\':\n                    *ptr2++ = '\\\\';\n                    break;\n\n                case '\\\"':\n                    *ptr2++ = '\\\"';\n                    break;\n\n                case '\\b':\n                    *ptr2++ = 'b';\n                    break;\n\n                case '\\f':\n                    *ptr2++ = 'f';\n                    break;\n\n                case '\\n':\n                    *ptr2++ = 'n';\n                    break;\n\n                case '\\r':\n                    *ptr2++ = 'r';\n                    break;\n\n                case '\\t':\n                    *ptr2++ = 't';\n                    break;\n\n                default:\n                \tsprintf(ptr2, \"u%04x\", token);\n                    ptr2 += 5;\n                    break;  /* escape and print */\n            }\n        }\n    }\n\n    *ptr2++ = '\\\"';\n    *ptr2++ = 0;\n    return out;\n}\n/* Invote print_string_ptr (which is useful) on an item. */\nstatic char *ICACHE_FLASH_ATTR\nprint_string(cJSON *item)\n{\n    return print_string_ptr(item->valuestring);\n}\n\n/* Predeclare these prototypes. */\nstatic const char *parse_value(cJSON *item, const char *value);\nstatic char *print_value(cJSON *item, int depth, int fmt);\nstatic const char *parse_array(cJSON *item, const char *value);\nstatic char *print_array(cJSON *item, int depth, int fmt);\nstatic const char *parse_object(cJSON *item, const char *value);\nstatic char *print_object(cJSON *item, int depth, int fmt);\n\n/* Utility to jump whitespace and cr/lf */\nstatic const char *ICACHE_FLASH_ATTR\nskip(const char *in)\n{\n    while (in && *in && (unsigned char)*in <= 32) {\n        in++;\n    }\n\n    return in;\n}\n\n/* Parse an object - create a new root, and populate. */\ncJSON *ICACHE_FLASH_ATTR\ncJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated)\n{\n    const char *end = 0;\n    cJSON *c = cJSON_New_Item();\n    ep = 0;\n\n    if (!c) {\n        return 0;    /* memory fail */\n    }\n\n    end = parse_value(c, skip(value));\n\n    if (!end)   {\n        cJSON_Delete(c);    /* parse failure. ep is set. */\n        return 0;\n    }\n\n    /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */\n    if (require_null_terminated) {\n        end = skip(end);\n\n        if (*end) {\n            cJSON_Delete(c);\n            ep = end;\n            return 0;\n        }\n    }\n\n    if (return_parse_end) {\n        *return_parse_end = end;\n    }\n\n    return c;\n}\n/* Default options for cJSON_Parse */\ncJSON *ICACHE_FLASH_ATTR\ncJSON_Parse(const char *value)\n{\n    return cJSON_ParseWithOpts(value, 0, 0);\n}\n\n/* Render a cJSON item/entity/structure to text. */\nchar *ICACHE_FLASH_ATTR\ncJSON_Print(cJSON *item)\n{\n    return print_value(item, 0, 1);\n}\nchar *ICACHE_FLASH_ATTR\ncJSON_PrintUnformatted(cJSON *item)\n{\n    return print_value(item, 0, 0);\n}\n\n/* Parser core - when encountering text, process appropriately. */\nstatic const char *ICACHE_FLASH_ATTR\nparse_value(cJSON *item, const char *value)\n{\n    if (!value) {\n        return 0;    /* Fail on null. */\n    }\n\n    if (!strncmp(value, \"null\", 4))    {\n        item->type = cJSON_NULL;\n        return value + 4;\n    }\n\n    if (!strncmp(value, \"false\", 5))   {\n        item->type = cJSON_False;\n        return value + 5;\n    }\n\n    if (!strncmp(value, \"true\", 4))    {\n        item->type = cJSON_True;\n        item->valueint = 1;\n        return value + 4;\n    }\n\n    if (*value == '\\\"')               {\n        return parse_string(item, value);\n    }\n\n    if (*value == '-' || (*value >= '0' && *value <= '9'))    {\n        return parse_number(item, value);\n    }\n\n    if (*value == '[')                {\n        return parse_array(item, value);\n    }\n\n    if (*value == '{')                {\n        return parse_object(item, value);\n    }\n\n    ep = value;\n    return 0;  /* failure. */\n}\n\n/* Render a value to text. */\nstatic char *ICACHE_FLASH_ATTR\nprint_value(cJSON *item, int depth, int fmt)\n{\n    char *out = 0;\n\n    if (!item) {\n        return 0;\n    }\n\n    switch ((item->type) & 255) {\n        case cJSON_NULL:\n            out = cJSON_strdup(\"null\");\n            break;\n\n        case cJSON_False:\n            out = cJSON_strdup(\"false\");\n            break;\n\n        case cJSON_True:\n            out = cJSON_strdup(\"true\");\n            break;\n\n        case cJSON_Number:\n            out = print_number(item);\n            break;\n\n        case cJSON_String:\n            out = print_string(item);\n            break;\n\n        case cJSON_Array:\n            out = print_array(item, depth, fmt);\n            break;\n\n        case cJSON_Object:\n            out = print_object(item, depth, fmt);\n            break;\n    }\n\n    return out;\n}\n\n/* Build an array from input text. */\nstatic const char *ICACHE_FLASH_ATTR\nparse_array(cJSON *item, const char *value)\n{\n    cJSON *child;\n\n    if (*value != '[')    {\n        ep = value;    /* not an array! */\n        return 0;\n    }\n\n    item->type = cJSON_Array;\n    value = skip(value + 1);\n\n    if (*value == ']') {\n        return value + 1;    /* empty array. */\n    }\n\n    item->child = child = cJSON_New_Item();\n\n    if (!item->child) {\n        return 0;    /* memory fail */\n    }\n\n    value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */\n\n    if (!value) {\n        return 0;\n    }\n\n    while (*value == ',') {\n        cJSON *new_item;\n\n        if (!(new_item = cJSON_New_Item())) {\n            return 0;    /* memory fail */\n        }\n\n        child->next = new_item;\n        new_item->prev = child;\n        child = new_item;\n        value = skip(parse_value(child, skip(value + 1)));\n\n        if (!value) {\n            return 0;    /* memory fail */\n        }\n    }\n\n    if (*value == ']') {\n        return value + 1;    /* end of array */\n    }\n\n    ep = value;\n    return 0;  /* malformed. */\n}\n\n/* Render an array to text */\nstatic char *ICACHE_FLASH_ATTR\nprint_array(cJSON *item, int depth, int fmt)\n{\n    char **entries;\n    char *out = 0, *ptr, *ret;\n    int len = 5;\n    cJSON *child = item->child;\n    int numentries = 0, i = 0, fail = 0;\n\n    /* How many entries in the array? */\n    while (child) {\n        numentries++, child = child->next;\n    }\n\n    /* Explicitly handle numentries==0 */\n    if (!numentries) {\n        out = (char *)cJSON_malloc(3);\n\n        if (out) {\n            strcpy(out, \"[]\");\n        }\n\n        return out;\n    }\n\n    /* Allocate an array to hold the values for each */\n    entries = (char **)cJSON_malloc(numentries * sizeof(char *));\n\n    if (!entries) {\n        return 0;\n    }\n\n    memset(entries, 0, numentries * sizeof(char *));\n    /* Retrieve all the results: */\n    child = item->child;\n\n    while (child && !fail) {\n        ret = print_value(child, depth + 1, fmt);\n        entries[i++] = ret;\n\n        if (ret) {\n            len += strlen(ret) + 2 + (fmt ? 1 : 0);\n        } else {\n            fail = 1;\n        }\n\n        child = child->next;\n    }\n\n    /* If we didn't fail, try to malloc the output string */\n    if (!fail) {\n        out = (char *)cJSON_malloc(len);\n    }\n\n    /* If that fails, we fail. */\n    if (!out) {\n        fail = 1;\n    }\n\n    /* Handle failure. */\n    if (fail) {\n        for (i = 0; i < numentries; i++) if (entries[i]) {\n                cJSON_free(entries[i]);\n            }\n\n        cJSON_free(entries);\n        return 0;\n    }\n\n    /* Compose the output array. */\n    *out = '[';\n    ptr = out + 1;\n    *ptr = 0;\n\n    for (i = 0; i < numentries; i++) {\n        strcpy(ptr, entries[i]);\n        ptr += strlen(entries[i]);\n\n        if (i != numentries - 1) {\n            *ptr++ = ',';\n\n            if (fmt) {\n                *ptr++ = ' ';\n            }*ptr = 0;\n        }\n\n        cJSON_free(entries[i]);\n    }\n\n    cJSON_free(entries);\n    *ptr++ = ']';\n    *ptr++ = 0;\n    return out;\n}\n\n/* Build an object from the text. */\nstatic const char *ICACHE_FLASH_ATTR\nparse_object(cJSON *item, const char *value)\n{\n    cJSON *child;\n\n    if (*value != '{')    {\n        ep = value;    /* not an object! */\n        return 0;\n    }\n\n    item->type = cJSON_Object;\n    value = skip(value + 1);\n\n    if (*value == '}') {\n        return value + 1;    /* empty array. */\n    }\n\n    item->child = child = cJSON_New_Item();\n\n    if (!item->child) {\n        return 0;\n    }\n\n    value = skip(parse_string(child, skip(value)));\n\n    if (!value) {\n        return 0;\n    }\n\n    child->string = child->valuestring;\n    child->valuestring = 0;\n\n    if (*value != ':') {\n        ep = value;    /* fail! */\n        return 0;\n    }\n\n    value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */\n\n    if (!value) {\n        return 0;\n    }\n\n    while (*value == ',') {\n        cJSON *new_item;\n\n        if (!(new_item = cJSON_New_Item())) {\n            return 0;    /* memory fail */\n        }\n\n        child->next = new_item;\n        new_item->prev = child;\n        child = new_item;\n        value = skip(parse_string(child, skip(value + 1)));\n\n        if (!value) {\n            return 0;\n        }\n\n        child->string = child->valuestring;\n        child->valuestring = 0;\n\n        if (*value != ':') {\n            ep = value;    /* fail! */\n            return 0;\n        }\n\n        value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */\n\n        if (!value) {\n            return 0;\n        }\n    }\n\n    if (*value == '}') {\n        return value + 1;    /* end of array */\n    }\n\n    ep = value;\n    return 0;  /* malformed. */\n}\n\n/* Render an object to text. */\nstatic char *ICACHE_FLASH_ATTR\nprint_object(cJSON *item, int depth, int fmt)\n{\n    char **entries = 0, **names = 0;\n    char *out = 0, *ptr, *ret, *str;\n    int len = 7, i = 0, j;\n    cJSON *child = item->child;\n    int numentries = 0, fail = 0;\n\n    /* Count the number of entries. */\n    while (child) {\n        numentries++, child = child->next;\n    }\n\n    /* Explicitly handle empty object case */\n    if (!numentries) {\n        out = (char *)cJSON_malloc(fmt ? depth + 4 : 3);\n\n        if (!out) {\n            return 0;\n        }\n\n        ptr = out;\n        *ptr++ = '{';\n\n        if (fmt) {\n            *ptr++ = '\\n';\n\n            for (i = 0; i < depth - 1; i++) {\n                *ptr++ = '\\t';\n            }\n        }\n\n        *ptr++ = '}';\n        *ptr++ = 0;\n        return out;\n    }\n\n    /* Allocate space for the names and the objects */\n    entries = (char **)cJSON_malloc(numentries * sizeof(char *));\n\n    if (!entries) {\n        return 0;\n    }\n\n    names = (char **)cJSON_malloc(numentries * sizeof(char *));\n\n    if (!names) {\n        cJSON_free(entries);\n        return 0;\n    }\n\n    memset(entries, 0, sizeof(char *)*numentries);\n    memset(names, 0, sizeof(char *)*numentries);\n\n    /* Collect all the results into our arrays: */\n    child = item->child;\n    depth++;\n\n    if (fmt) {\n        len += depth;\n    }\n\n    while (child) {\n        names[i] = str = print_string_ptr(child->string);\n        entries[i++] = ret = print_value(child, depth, fmt);\n\n        if (str && ret) {\n            len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);\n        } else {\n            fail = 1;\n        }\n\n        child = child->next;\n    }\n\n    /* Try to allocate the output string */\n    if (!fail) {\n        out = (char *)cJSON_malloc(len);\n    }\n\n    if (!out) {\n        fail = 1;\n    }\n\n    /* Handle failure */\n    if (fail) {\n        for (i = 0; i < numentries; i++) {\n            if (names[i]) {\n                cJSON_free(names[i]);\n            }\n\n            if (entries[i]) {\n                cJSON_free(entries[i]);\n            }\n        }\n\n        cJSON_free(names);\n        cJSON_free(entries);\n        return 0;\n    }\n\n    /* Compose the output: */\n    *out = '{';\n    ptr = out + 1;\n\n    if (fmt) {\n        *ptr++ = '\\n';\n    }*ptr = 0;\n\n    for (i = 0; i < numentries; i++) {\n        if (fmt) for (j = 0; j < depth; j++) {\n                *ptr++ = '\\t';\n            }\n\n        strcpy(ptr, names[i]);\n        ptr += strlen(names[i]);\n        *ptr++ = ':';\n\n        if (fmt) {\n            *ptr++ = '\\t';\n        }\n\n        strcpy(ptr, entries[i]);\n        ptr += strlen(entries[i]);\n\n        if (i != numentries - 1) {\n            *ptr++ = ',';\n        }\n\n        if (fmt) {\n            *ptr++ = '\\n';\n        }*ptr = 0;\n\n        cJSON_free(names[i]);\n        cJSON_free(entries[i]);\n    }\n\n    cJSON_free(names);\n    cJSON_free(entries);\n\n    if (fmt) for (i = 0; i < depth - 1; i++) {\n            *ptr++ = '\\t';\n        }\n\n    *ptr++ = '}';\n    *ptr++ = 0;\n    return out;\n}\n\n/* Get Array size/item / object item. */\nint ICACHE_FLASH_ATTR cJSON_GetArraySize(cJSON *array)\n{\n    cJSON *c = array->child;\n    int i = 0;\n\n    while (c) {\n        i++, c = c->next;\n    }\n\n    return i;\n}\ncJSON *ICACHE_FLASH_ATTR cJSON_GetArrayItem(cJSON *array, int item)\n{\n    cJSON *c = array->child;\n\n    while (c && item > 0) {\n        item--, c = c->next;\n    }\n\n    return c;\n}\ncJSON *ICACHE_FLASH_ATTR cJSON_GetObjectItem(cJSON *object, const char *string)\n{\n    cJSON *c = object->child;\n\n    while (c && cJSON_strcasecmp(c->string, string)) {\n        c = c->next;\n    }\n\n    return c;\n}\n\n/* Utility for array list handling. */\nstatic void ICACHE_FLASH_ATTR suffix_object(cJSON *prev, cJSON *item)\n{\n    prev->next = item;\n    item->prev = prev;\n}\n/* Utility for handling references. */\nstatic cJSON *ICACHE_FLASH_ATTR create_reference(cJSON *item)\n{\n    cJSON *ref = cJSON_New_Item();\n\n    if (!ref) {\n        return 0;\n    }\n\n    memcpy(ref, item, sizeof(cJSON));\n    ref->string = 0;\n    ref->type |= cJSON_IsReference;\n    ref->next = ref->prev = 0;\n    return ref;\n}\n\n/* Add item to array/object. */\nvoid ICACHE_FLASH_ATTR cJSON_AddItemToArray(cJSON *array, cJSON *item)\n{\n    cJSON *c = array->child;\n\n    if (!item) {\n        return;\n    }\n\n    if (!c) {\n        array->child = item;\n    } else {\n        while (c && c->next) {\n            c = c->next;\n        }\n\n        suffix_object(c, item);\n    }\n}\nvoid ICACHE_FLASH_ATTR cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)\n{\n    if (!item) {\n        return;\n    }\n\n    if (item->string) {\n        cJSON_free(item->string);\n    }\n\n    item->string = cJSON_strdup(string);\n    cJSON_AddItemToArray(object, item);\n}\nvoid  ICACHE_FLASH_ATTR  cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)\n{\n    cJSON_AddItemToArray(array, create_reference(item));\n}\nvoid  ICACHE_FLASH_ATTR  cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)\n{\n    cJSON_AddItemToObject(object, string, create_reference(item));\n}\n\ncJSON *ICACHE_FLASH_ATTR cJSON_DetachItemFromArray(cJSON *array, int which)\n{\n    cJSON *c = array->child;\n\n    while (c && which > 0) {\n        c = c->next, which--;\n    }\n\n    if (!c) {\n        return 0;\n    }\n\n    if (c->prev) {\n        c->prev->next = c->next;\n    }\n\n    if (c->next) {\n        c->next->prev = c->prev;\n    }\n\n    if (c == array->child) {\n        array->child = c->next;\n    }\n\n    c->prev = c->next = 0;\n    return c;\n}\nvoid  ICACHE_FLASH_ATTR cJSON_DeleteItemFromArray(cJSON *array, int which)\n{\n    cJSON_Delete(cJSON_DetachItemFromArray(array, which));\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_DetachItemFromObject(cJSON *object, const char *string)\n{\n    int i = 0;\n    cJSON *c = object->child;\n\n    while (c && cJSON_strcasecmp(c->string, string)) {\n        i++, c = c->next;\n    }\n\n    if (c) {\n        return cJSON_DetachItemFromArray(object, i);\n    }\n\n    return 0;\n}\nvoid ICACHE_FLASH_ATTR\ncJSON_DeleteItemFromObject(cJSON *object, const char *string)\n{\n    cJSON_Delete(cJSON_DetachItemFromObject(object, string));\n}\n\n/* Replace array/object items with new ones. */\nvoid ICACHE_FLASH_ATTR\ncJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)\n{\n    cJSON *c = array->child;\n\n    while (c && which > 0) {\n        c = c->next, which--;\n    }\n\n    if (!c) {\n        return;\n    }\n\n    newitem->next = c->next;\n    newitem->prev = c->prev;\n\n    if (newitem->next) {\n        newitem->next->prev = newitem;\n    }\n\n    if (c == array->child) {\n        array->child = newitem;\n    } else {\n        newitem->prev->next = newitem;\n    }\n\n    c->next = c->prev = 0;\n    cJSON_Delete(c);\n}\nvoid ICACHE_FLASH_ATTR\ncJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)\n{\n    int i = 0;\n    cJSON *c = object->child;\n\n    while (c && cJSON_strcasecmp(c->string, string)) {\n        i++, c = c->next;\n    }\n\n    if (c) {\n        newitem->string = cJSON_strdup(string);\n        cJSON_ReplaceItemInArray(object, i, newitem);\n    }\n}\n\n/* Create basic types: */\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateNull(void)\n{\n    cJSON *item = cJSON_New_Item();\n\n    if (item) {\n        item->type = cJSON_NULL;\n    }\n\n    return item;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateTrue(void)\n{\n    cJSON *item = cJSON_New_Item();\n\n    if (item) {\n        item->type = cJSON_True;\n    }\n\n    return item;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateFalse(void)\n{\n    cJSON *item = cJSON_New_Item();\n\n    if (item) {\n        item->type = cJSON_False;\n    }\n\n    return item;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateBool(int b)\n{\n    cJSON *item = cJSON_New_Item();\n\n    if (item) {\n        item->type = b ? cJSON_True : cJSON_False;\n    }\n\n    return item;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateNumber(double num)\n{\n    cJSON *item = cJSON_New_Item();\n\n    if (item) {\n        item->type = cJSON_Number;\n        item->valuedouble = num;\n        item->valueint = (int)num;\n    }\n\n    return item;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateString(const char *string)\n{\n    cJSON *item = cJSON_New_Item();\n\n    if (item) {\n        item->type = cJSON_String;\n        item->valuestring = cJSON_strdup(string);\n    }\n\n    return item;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateArray(void)\n{\n    cJSON *item = cJSON_New_Item();\n\n    if (item) {\n        item->type = cJSON_Array;\n    }\n\n    return item;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateObject(void)\n{\n    cJSON *item = cJSON_New_Item();\n\n    if (item) {\n        item->type = cJSON_Object;\n    }\n\n    return item;\n}\n\n/* Create Arrays: */\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateIntArray(const int *numbers, int count)\n{\n    int i;\n    cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();\n\n    for (i = 0; a && i < count; i++) {\n        n = cJSON_CreateNumber(numbers[i]);\n\n        if (!i) {\n            a->child = n;\n        } else {\n            suffix_object(p, n);\n        }\n\n        p = n;\n    }\n\n    return a;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateFloatArray(const float *numbers, int count)\n{\n    int i;\n    cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();\n\n    for (i = 0; a && i < count; i++) {\n        n = cJSON_CreateNumber(numbers[i]);\n\n        if (!i) {\n            a->child = n;\n        } else {\n            suffix_object(p, n);\n        }\n\n        p = n;\n    }\n\n    return a;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateDoubleArray(const double *numbers, int count)\n{\n    int i;\n    cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();\n\n    for (i = 0; a && i < count; i++) {\n        n = cJSON_CreateNumber(numbers[i]);\n\n        if (!i) {\n            a->child = n;\n        } else {\n            suffix_object(p, n);\n        }\n\n        p = n;\n    }\n\n    return a;\n}\ncJSON *ICACHE_FLASH_ATTR\ncJSON_CreateStringArray(const char **strings, int count)\n{\n    int i;\n    cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();\n\n    for (i = 0; a && i < count; i++) {\n        n = cJSON_CreateString(strings[i]);\n\n        if (!i) {\n            a->child = n;\n        } else {\n            suffix_object(p, n);\n        }\n\n        p = n;\n    }\n\n    return a;\n}\n\n/* Duplication */\ncJSON *ICACHE_FLASH_ATTR\ncJSON_Duplicate(cJSON *item, int recurse)\n{\n    cJSON *newitem, *cptr, *nptr = 0, *newchild;\n\n    /* Bail on bad ptr */\n    if (!item) {\n        return 0;\n    }\n\n    /* Create new item */\n    newitem = cJSON_New_Item();\n\n    if (!newitem) {\n        return 0;\n    }\n\n    /* Copy over all vars */\n    newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble;\n\n    if (item->valuestring)  {\n        newitem->valuestring = cJSON_strdup(item->valuestring);\n\n        if (!newitem->valuestring)  {\n            cJSON_Delete(newitem);\n            return 0;\n        }\n    }\n\n    if (item->string)       {\n        newitem->string = cJSON_strdup(item->string);\n\n        if (!newitem->string)       {\n            cJSON_Delete(newitem);\n            return 0;\n        }\n    }\n\n    /* If non-recursive, then we're done! */\n    if (!recurse) {\n        return newitem;\n    }\n\n    /* Walk the ->next chain for the child. */\n    cptr = item->child;\n\n    while (cptr) {\n        newchild = cJSON_Duplicate(cptr, 1);    /* Duplicate (with recurse) each item in the ->next chain */\n\n        if (!newchild) {\n            cJSON_Delete(newitem);\n            return 0;\n        }\n\n        if (nptr)   {\n            nptr->next = newchild, newchild->prev = nptr;    /* If newitem->child already set, then crosswire ->prev and ->next and move on */\n            nptr = newchild;\n        } else        {\n            newitem->child = newchild;    /* Set newitem->child and move to it */\n            nptr = newchild;\n        }\n\n        cptr = cptr->next;\n    }\n\n    return newitem;\n}\n\nvoid ICACHE_FLASH_ATTR cJSON_Minify(char *json)\n{\n    char *into = json;\n\n    while (*json) {\n        if (*json == ' ') {\n            json++;\n        } else if (*json == '\\t') {\n            json++;    // Whitespace characters.\n        } else if (*json == '\\r') {\n            json++;\n        } else if (*json == '\\n') {\n            json++;\n        } else if (*json == '/' && json[1] == '/')  while (*json && *json != '\\n') {\n                json++;    // double-slash comments, to end of line.\n            }\n        else if (*json == '/' && json[1] == '*') {\n            while (*json && !(*json == '*' && json[1] == '/')) {\n                json++;    // multiline comments.\n            }\n\n            json += 2;\n        } else if (*json == '\\\"') {\n            *into++ = *json++;    // string literals, which are \\\" sensitive.\n\n            while (*json && *json != '\\\"') {\n                if (*json == '\\\\') {\n                    *into++ = *json++;\n                }*into++ = *json++;\n            }*into++ = *json++;\n        } else {\n            *into++ = *json++;    // All other characters.\n        }\n    }\n\n    *into = 0;  // and null-terminate.\n}\n\n"
  },
  {
    "path": "app/libc/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = liblibc.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../wofs\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/libc/c_ctype.c",
    "content": "#include \"c_ctype.h\"\n#include \"c_types.h\"\n\n// int isalnum(int c){}\n// int isalpha(int c){}\n// int iscntrl(int c){}\n// int isdigit(int c){}\n// // int isgraph(int c){}\n// int islower(int c){}\n// int isprint(int c){}\n// int ispunct(int c){}\n// int isspace(int c){}\n// int isupper(int c){}\n// int isxdigit(int c){}\n// int tolower(int c){}\n// int toupper(int c){}\n"
  },
  {
    "path": "app/libc/c_ctype.h",
    "content": "#ifndef _C_CTYPE_H_\n#define _C_CTYPE_H_\n\n#if 0\nint isalnum(int);\nint isalpha(int);\nint iscntrl(int);\nint isdigit(int);\n// int isgraph(int);\nint islower(int);\nint isprint(int);\nint ispunct(int);\nint isspace(int);\nint isupper(int);\nint isxdigit(int);\nint tolower(int);\nint toupper(int);\n\n#if !defined(__STRICT_ANSI__) || defined(__cplusplus) || __STDC_VERSION__ >= 199901L\n// int isblank(int);\n#endif\n\n#ifndef __STRICT_ANSI__\n// int isascii(int);\n// int toascii(int);\n#define _tolower(__c) ((unsigned char)(__c) - 'A' + 'a')\n#define _toupper(__c) ((unsigned char)(__c) - 'a' + 'A')\n#endif\n\n#define\t_U\t01\n#define\t_L\t02\n#define\t_N\t04\n#define\t_S\t010\n#define _P\t020\n#define _C\t040\n#define _X\t0100\n#define\t_B\t0200\n\n/* For C++ backward-compatibility only.  */\n// extern\tchar\t_ctype_[];\n#endif\n#endif /* _C_CTYPE_H_ */\n"
  },
  {
    "path": "app/libc/c_errno.h",
    "content": "#ifndef __c_errno_h\n#define __c_errno_h\n\n#include <errno.h>\n// #ifndef errno\n// extern int errno;\n// #endif\n\n// #define EDOM    1\n// #define ERANGE \t2\n// #define EILSEQ  4\n// #define ESIGNUM 3\n// #define EINVAL  5\n// #define ENOMEM  6\n\n#endif\n\n/* end of c_errno.h */\n\n"
  },
  {
    "path": "app/libc/c_fcntl.h",
    "content": "#ifndef __c_fcntl_h\n#define __c_fcntl_h\n\n#include <fcntl.h>\n\n#endif\n\n/* end of c_fcntl.h */\n\n"
  },
  {
    "path": "app/libc/c_limits.h",
    "content": "#ifndef __c_limits_h\n#define __c_limits_h\n\n#include <limits.h>\n#if 0\n#define CHAR_BIT 8\n    /* max number of bits for smallest object that is not a bit-field (byte) */\n#define SCHAR_MIN (-128)\n    /* mimimum value for an object of type signed char */\n#define SCHAR_MAX 127\n    /* maximum value for an object of type signed char */\n#define UCHAR_MAX 255\n    /* maximum value for an object of type unsigned char */\n#ifdef __FEATURE_SIGNED_CHAR\n  #define CHAR_MIN (-128)\n      /* minimum value for an object of type char */\n  #define CHAR_MAX 127\n      /* maximum value for an object of type char */\n#else\n  #define CHAR_MIN 0\n      /* minimum value for an object of type char */\n  #define CHAR_MAX 255\n      /* maximum value for an object of type char */\n#endif\n\n#define SHRT_MIN  (-0x8000)\n    /* minimum value for an object of type short int */\n#define SHRT_MAX  0x7fff\n    /* maximum value for an object of type short int */\n#define USHRT_MAX 65535\n    /* maximum value for an object of type unsigned short int */\n#define INT_MIN   (~0x7fffffff)  /* -2147483648 and 0x80000000 are unsigned */\n    /* minimum value for an object of type int */\n#define INT_MAX   0x7fffffff\n    /* maximum value for an object of type int */\n#define UINT_MAX  0xffffffffU\n    /* maximum value for an object of type unsigned int */\n#define LONG_MIN  (~0x7fffffffL)\n    /* minimum value for an object of type long int */\n#define LONG_MAX  0x7fffffffL\n    /* maximum value for an object of type long int */\n#define ULONG_MAX 0xffffffffUL\n    /* maximum value for an object of type unsigned long int */\n#if !defined(__STRICT_ANSI__) || (defined(__STDC_VERSION__) && 199901L <= __STDC_VERSION__)\n  #define LLONG_MIN  (~0x7fffffffffffffffLL)\n      /* minimum value for an object of type long long int */\n  #define LLONG_MAX    0x7fffffffffffffffLL\n      /* maximum value for an object of type long long int */\n  #define ULLONG_MAX   0xffffffffffffffffULL\n      /* maximum value for an object of type unsigned long int */\n#endif\n\n#endif\n\n#endif\n\n/* end of c_limits.h */\n\n"
  },
  {
    "path": "app/libc/c_locale.h",
    "content": "/*\n\tc_locale.h\n\tValues appropriate for the formatting of monetary and other\n\tnumberic quantities.\n*/\n\n#ifndef _C_LOCALE_H_\n#define _C_LOCALE_H_\n\n#include <locale.h>\n  \n#if 0\n#ifndef NULL\n#define NULL    0\n#endif\n\n#define LC_ALL\t    0\n#define LC_COLLATE  1\n#define LC_CTYPE    2\n#define LC_MONETARY 3\n#define LC_NUMERIC  4\n#define LC_TIME     5\n#define LC_MESSAGES 6\n\nstruct lconv\n{\n  char *decimal_point;\n  char *thousands_sep;\n  char *grouping;\n  char *int_curr_symbol;\n  char *currency_symbol;\n  char *mon_decimal_point;\n  char *mon_thousands_sep;\n  char *mon_grouping;\n  char *positive_sign;\n  char *negative_sign;\n  char int_frac_digits;\n  char frac_digits;\n  char p_cs_precedes;\n  char p_sep_by_space;\n  char n_cs_precedes;\n  char n_sep_by_space;\n  char p_sign_posn;\n  char n_sign_posn;\n  char int_n_cs_precedes;\n  char int_n_sep_by_space;\n  char int_n_sign_posn;\n  char int_p_cs_precedes;\n  char int_p_sep_by_space;\n  char int_p_sign_posn;\n};\n\n#ifndef _REENT_ONLY\n// char *setlocale(int category, const char *locale);\nstruct lconv *localeconv(void);\n#endif\n\n// struct _reent;\n// char *_setlocale_r(struct _reent *, int category, const char *locale);\n// struct lconv *_localeconv_r(struct _reent *);\n#endif\n#endif /* _C_LOCALE_H_ */\n"
  },
  {
    "path": "app/libc/c_math.c",
    "content": "#include \"c_math.h\"\n#include \"c_types.h\"\n\ndouble floor(double x)\n{\n    return (double) (x < 0.f ? (((int) x) - 1) : ((int) x));\n}\n\ndouble pow(double x, double y)\n{\n#define MAXEXP 2031     /* (MAX_EXP * 16) - 1           */\n#define MINEXP -2047        /* (MIN_EXP * 16) - 1           */\n#define HUGE MAXFLOAT\n    double a1[] =\n    {\n        1.0,\n        0.95760328069857365,\n        0.91700404320467123,\n        0.87812608018664974,\n        0.84089641525371454,\n        0.80524516597462716,\n        0.77110541270397041,\n        0.73841307296974966,\n        0.70710678118654752,\n        0.67712777346844637,\n        0.64841977732550483,\n        0.62092890603674203,\n        0.59460355750136054,\n        0.56939431737834583,\n        0.54525386633262883,\n        0.52213689121370692,\n        0.50000000000000000\n    };\n    double a2[] =\n    {\n        0.24114209503420288E-17,\n        0.92291566937243079E-18,\n        -0.15241915231122319E-17,\n        -0.35421849765286817E-17,\n        -0.31286215245415074E-17,\n        -0.44654376565694490E-17,\n        0.29306999570789681E-17,\n        0.11260851040933474E-17\n    };\n    double p1 = 0.833333333333332114e-1;\n    double p2 = 0.125000000005037992e-1;\n    double p3 = 0.223214212859242590e-2;\n    double p4 = 0.434457756721631196e-3;\n    double q1 = 0.693147180559945296e0;\n    double q2 = 0.240226506959095371e0;\n    double q3 = 0.555041086640855953e-1;\n    double q4 = 0.961812905951724170e-2;\n    double q5 = 0.133335413135857847e-2;\n    double q6 = 0.154002904409897646e-3;\n    double q7 = 0.149288526805956082e-4;\n    double k = 0.442695040888963407;\n\n    double frexp(), g, ldexp(), r, u1, u2, v, w, w1, w2, y1, y2, z;\n    int iw1, m, p;\n\n    if (y == 0.0)\n        return (1.0);\n    if (x <= 0.0)\n    {\n        if (x == 0.0)\n        {\n            if (y > 0.0)\n                return (x);\n            //cmemsg(FP_POWO, &y);\n            //return(HUGE);\n        }\n        else\n        {\n            //cmemsg(FP_POWN, &x);\n            x = -x;\n        }\n    }\n    g = frexp(x, &m);\n    p = 0;\n    if (g <= a1[8])\n        p = 8;\n    if (g <= a1[p + 4])\n        p += 4;\n    if (g <= a1[p + 2])\n        p += 2;\n    p++;\n    z = ((g - a1[p]) - a2[p / 2]) / (g + a1[p]);\n    z += z;\n    v = z * z;\n    r = (((p4 * v + p3) * v + p2) * v + p1) * v * z;\n    r += k * r;\n    u2 = (r + z * k) + z;\n    u1 = 0.0625 * (double)(16 * m - p);\n    y1 = 0.0625 * (double)((int)(16.0 * y));\n    y2 = y - y1;\n    w = u2 * y + u1 * y2;\n    w1 = 0.0625 * (double)((int)(16.0 * w));\n    w2 = w - w1;\n    w = w1 + u1 * y1;\n    w1 = 0.0625 * (double)((int)(16.0 * w));\n    w2 += (w - w1);\n    w = 0.0625 * (double)((int)(16.0 * w2));\n    iw1 = 16.0 * (w1 + w);\n    w2 -= w;\n    while (w2 > 0.0)\n    {\n        iw1++;\n        w2 -= 0.0625;\n    }\n    if (iw1 > MAXEXP)\n    {\n        //cmemsg(FP_POWO, &y);\n        return (HUGE);\n    }\n    if (iw1 < MINEXP)\n    {\n        //cmemsg(FP_POWU, &y);\n        return (0.0);\n    }\n    m = iw1 / 16;\n    if (iw1 >= 0)\n        m++;\n    p = 16 * m - iw1;\n    z = ((((((q7 * w2 + q6) * w2 + q5) * w2 + q4) * w2 + q3) * w2 + q2) * w2 + q1) * w2;\n    z = a1[p] + a1[p] * z;\n    return (ldexp(z, m));\n}\n\n#if 0\n#ifndef __math_68881\ndouble atan(double x)\n{\n    return x;\n}\ndouble cos(double x)\n{\n    return x;\n}\ndouble sin(double x)\n{\n    return x;\n}\ndouble tan(double x)\n{\n    return x;\n}\ndouble tanh(double x)\n{\n    return x;\n}\ndouble frexp(double x, int *y)\n{\n    return x;\n}\ndouble modf(double x, double *y)\n{\n    return x;\n}\ndouble ceil(double x)\n{\n    return x;\n}\ndouble fabs(double x)\n{\n    return x;\n}\ndouble floor(double x)\n{\n    return x;\n}\n#endif /* ! defined (__math_68881) */\n\n/* Non reentrant ANSI C functions.  */\n\n#ifndef _REENT_ONLY\n#ifndef __math_68881\ndouble acos(double x)\n{\n    return x;\n}\ndouble asin(double x)\n{\n    return x;\n}\ndouble atan2(double x, double y)\n{\n    return x;\n}\ndouble cosh(double x)\n{\n    return x;\n}\ndouble sinh(double x)\n{\n    return x;\n}\ndouble exp(double x)\n{\n    return x;\n}\ndouble ldexp(double x, int y)\n{\n    return x;\n}\ndouble log(double x)\n{\n    return x;\n}\ndouble log10(double x)\n{\n    return x;\n}\ndouble pow(double x, double y)\n{\n    return x;\n}\ndouble sqrt(double x)\n{\n    return x;\n}\ndouble fmod(double x, double y)\n{\n    return x;\n}\n#endif /* ! defined (__math_68881) */\n#endif /* ! defined (_REENT_ONLY) */\n#endif\n"
  },
  {
    "path": "app/libc/c_math.h",
    "content": "#ifndef  _C_MATH_H_\n#define  _C_MATH_H_\n#include <math.h>\n\ndouble floor(double);\ndouble pow(double, double);\n\n#if 0\n#ifndef HUGE_VAL\n  #define HUGE_VAL (1.0e99)\n #endif\n\n #ifndef HUGE_VALF\n  #define HUGE_VALF (1.0e999999999F)\n #endif\n\n #if !defined(HUGE_VALL)  &&  defined(_HAVE_LONG_DOUBLE)\n  #define HUGE_VALL (1.0e999999999L)\n #endif\n\n #if !defined(INFINITY)\n  #define INFINITY (HUGE_VALF)\n #endif\n\n\n/* Reentrant ANSI C functions.  */\n\n#ifndef __math_68881\n// double atan(double);\n// double cos(double);\n// double sin(double);\n// double tan(double);\n// double tanh(double);\n// double frexp(double, int *);\n// double modf(double, double *);\n// double ceil(double);\n// double fabs(double);\n// double floor(double);\n#endif /* ! defined (__math_68881) */\n\n/* Non reentrant ANSI C functions.  */\n\n#ifndef _REENT_ONLY\n#ifndef __math_68881\n// double acos(double);\n// double asin(double);\n// double atan2(double, double);\n// double cosh(double);\n// double sinh(double);\n// double exp(double);\n// double ldexp(double, int);\n// double log(double);\n// double log10(double);\n// double pow(double, double);\n// double sqrt(double);\n// double fmod(double, double);\n#endif /* ! defined (__math_68881) */\n#endif /* ! defined (_REENT_ONLY) */\n\n#endif\n\n#endif /* _MATH_H_ */\n"
  },
  {
    "path": "app/libc/c_signal.h",
    "content": "#ifndef _C_SIGNAL_H_\n#define _C_SIGNAL_H_\n\n#include <signal.h>\n\n#endif /* _C_SIGNAL_H_ */\n"
  },
  {
    "path": "app/libc/c_stdarg.h",
    "content": "#ifndef __c_stdarg_h\n#define __c_stdarg_h\n\n#if defined(__GNUC__)\n\n#include <stdarg.h>\n\n#else\n\ntypedef char * va_list;\n\n#define _INTSIZEOF(n)   ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)) \n\n#define va_start(ap,v)  (ap = (va_list)&v + _INTSIZEOF(v))\n#define va_arg(ap,t)    (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))\n#define va_end(ap)      (ap = (va_list)0)\n\n#endif\n\n#endif\n\n/* end of c_stdarg.h */\n"
  },
  {
    "path": "app/libc/c_stddef.h",
    "content": "#ifndef __c_stddef_h\n#define __c_stddef_h\n\ntypedef signed int ptrdiff_t;\n\n#if !defined(offsetof)\n#define offsetof(s, m)   (size_t)&(((s *)0)->m)\n#endif \n\n#if !defined(__size_t)\n  #define __size_t 1\n  typedef unsigned int size_t;   /* others (e.g. <stdio.h>) also define */\n   /* the unsigned integral type of the result of the sizeof operator. */\n#endif\n\n#undef NULL  /* others (e.g. <stdio.h>) also define */\n#define NULL 0\n   /* null pointer constant. */\n\n#endif\n\n/* end of c_stddef.h */\n\n"
  },
  {
    "path": "app/libc/c_stdint.h",
    "content": "#ifndef __c_stdint_h\n#define __c_stdint_h\n\n#include \"c_types.h\"\n#if 0\n/*\n * Depending on compiler version __int64 or __INT64_TYPE__ should be defined.\n */\n#ifndef __int64\n  #ifdef __INT64_TYPE__\n    #define __int64 __INT64_TYPE__\n  #else\n    #define __int64 long long\n  #endif\n  /* On some architectures neither of these may be defined - if so, fall\n     through and error out if used. */\n#endif\n\n  #ifndef __STDINT_DECLS\n  #define __STDINT_DECLS\n\n    #undef __CLIBNS\n\n    #ifdef __cplusplus\n      namespace std {\n          #define __CLIBNS std::\n          extern \"C\" {\n    #else\n      #define __CLIBNS\n    #endif  /* __cplusplus */\n\n\n/*\n * 'signed' is redundant below, except for 'signed char' and if\n * the typedef is used to declare a bitfield.\n * '__int64' is used instead of 'long long' so that this header\n * can be used in --strict mode.\n */\n\n    /* 7.18.1.1 */\n\n    /* exact-width signed integer types */\ntypedef   signed          char int8_t;\ntypedef   signed short     int int16_t;\ntypedef   signed           int int32_t;\ntypedef   signed       __int64 int64_t;\n\n    /* exact-width unsigned integer types */\ntypedef unsigned          char uint8_t;\ntypedef unsigned short     int uint16_t;\ntypedef unsigned           int uint32_t;\ntypedef unsigned       __int64 uint64_t;\n\n    /* 7.18.1.2 */\n\n    /* smallest type of at least n bits */\n    /* minimum-width signed integer types */\ntypedef   signed          char int_least8_t;\ntypedef   signed short     int int_least16_t;\ntypedef   signed           int int_least32_t;\ntypedef   signed       __int64 int_least64_t;\n\n    /* minimum-width unsigned integer types */\ntypedef unsigned          char uint_least8_t;\ntypedef unsigned short     int uint_least16_t;\ntypedef unsigned           int uint_least32_t;\ntypedef unsigned       __int64 uint_least64_t;\n\n    /* 7.18.1.3 */\n\n    /* fastest minimum-width signed integer types */\ntypedef   signed           int int_fast8_t;\ntypedef   signed           int int_fast16_t;\ntypedef   signed           int int_fast32_t;\ntypedef   signed       __int64 int_fast64_t;\n\n    /* fastest minimum-width unsigned integer types */\ntypedef unsigned           int uint_fast8_t;\ntypedef unsigned           int uint_fast16_t;\ntypedef unsigned           int uint_fast32_t;\ntypedef unsigned       __int64 uint_fast64_t;\n\n    /* 7.18.1.4 integer types capable of holding object pointers */\ntypedef   signed           int intptr_t;\ntypedef unsigned           int uintptr_t;\n\n    /* 7.18.1.5 greatest-width integer types */\ntypedef   signed       __int64 intmax_t;\ntypedef unsigned       __int64 uintmax_t;\n\n\n#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)\n\n    /* 7.18.2.1 */\n\n    /* minimum values of exact-width signed integer types */\n#define INT8_MIN                   -128\n#define INT16_MIN                -32768\n#define INT32_MIN          (~0x7fffffff)   /* -2147483648 is unsigned */\n#define INT64_MIN  __ESCAPE__(~0x7fffffffffffffffll) /* -9223372036854775808 is unsigned */\n\n    /* maximum values of exact-width signed integer types */\n#define INT8_MAX                    127\n#define INT16_MAX                 32767\n#define INT32_MAX            2147483647\n#define INT64_MAX  __ESCAPE__(9223372036854775807ll)\n\n    /* maximum values of exact-width unsigned integer types */\n#define UINT8_MAX                   255\n#define UINT16_MAX                65535\n#define UINT32_MAX           4294967295u\n#define UINT64_MAX __ESCAPE__(18446744073709551615ull)\n\n    /* 7.18.2.2 */\n\n    /* minimum values of minimum-width signed integer types */\n#define INT_LEAST8_MIN                   -128\n#define INT_LEAST16_MIN                -32768\n#define INT_LEAST32_MIN          (~0x7fffffff)\n#define INT_LEAST64_MIN  __ESCAPE__(~0x7fffffffffffffffll)\n\n    /* maximum values of minimum-width signed integer types */\n#define INT_LEAST8_MAX                    127\n#define INT_LEAST16_MAX                 32767\n#define INT_LEAST32_MAX            2147483647\n#define INT_LEAST64_MAX  __ESCAPE__(9223372036854775807ll)\n\n    /* maximum values of minimum-width unsigned integer types */\n#define UINT_LEAST8_MAX                   255\n#define UINT_LEAST16_MAX                65535\n#define UINT_LEAST32_MAX           4294967295u\n#define UINT_LEAST64_MAX __ESCAPE__(18446744073709551615ull)\n\n    /* 7.18.2.3 */\n\n    /* minimum values of fastest minimum-width signed integer types */\n#define INT_FAST8_MIN           (~0x7fffffff)\n#define INT_FAST16_MIN          (~0x7fffffff)\n#define INT_FAST32_MIN          (~0x7fffffff)\n#define INT_FAST64_MIN  __ESCAPE__(~0x7fffffffffffffffll)\n\n    /* maximum values of fastest minimum-width signed integer types */\n#define INT_FAST8_MAX             2147483647\n#define INT_FAST16_MAX            2147483647\n#define INT_FAST32_MAX            2147483647\n#define INT_FAST64_MAX  __ESCAPE__(9223372036854775807ll)\n\n    /* maximum values of fastest minimum-width unsigned integer types */\n#define UINT_FAST8_MAX            4294967295u\n#define UINT_FAST16_MAX           4294967295u\n#define UINT_FAST32_MAX           4294967295u\n#define UINT_FAST64_MAX __ESCAPE__(18446744073709551615ull)\n\n    /* 7.18.2.4 */\n\n    /* minimum value of pointer-holding signed integer type */\n#define INTPTR_MIN (~0x7fffffff)\n\n    /* maximum value of pointer-holding signed integer type */\n#define INTPTR_MAX   2147483647\n\n    /* maximum value of pointer-holding unsigned integer type */\n#define UINTPTR_MAX  4294967295u\n\n    /* 7.18.2.5 */\n\n    /* minimum value of greatest-width signed integer type */\n#define INTMAX_MIN  __ESCAPE__(~0x7fffffffffffffffll)\n\n    /* maximum value of greatest-width signed integer type */\n#define INTMAX_MAX  __ESCAPE__(9223372036854775807ll)\n\n    /* maximum value of greatest-width unsigned integer type */\n#define UINTMAX_MAX __ESCAPE__(18446744073709551615ull)\n\n    /* 7.18.3 */\n\n    /* limits of ptrdiff_t */\n#define PTRDIFF_MIN (~0x7fffffff)\n#define PTRDIFF_MAX   2147483647\n\n    /* limits of sig_atomic_t */\n#define SIG_ATOMIC_MIN (~0x7fffffff)\n#define SIG_ATOMIC_MAX   2147483647\n\n    /* limit of size_t */\n#define SIZE_MAX 4294967295u\n\n    /* limits of wchar_t */\n    /* NB we have to undef and redef because they're defined in both\n     * stdint.h and wchar.h */\n#undef WCHAR_MIN\n#undef WCHAR_MAX\n\n#if defined(__WCHAR32) || (defined(__ARM_SIZEOF_WCHAR_T) && __ARM_SIZEOF_WCHAR_T == 4)\n  #define WCHAR_MIN   0\n  #define WCHAR_MAX   0xffffffffU\n#else\n  #define WCHAR_MIN   0\n  #define WCHAR_MAX   65535\n#endif\n\n    /* limits of wint_t */\n#define WINT_MIN (~0x7fffffff)\n#define WINT_MAX 2147483647\n\n#endif /* __STDC_LIMIT_MACROS */\n\n#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)\n\n    /* 7.18.4.1 macros for minimum-width integer constants */\n#define INT8_C(x)   (x)\n#define INT16_C(x)  (x)\n#define INT32_C(x)  (x)\n#define INT64_C(x)  __ESCAPE__(x ## ll)\n\n#define UINT8_C(x)  (x ## u)\n#define UINT16_C(x) (x ## u)\n#define UINT32_C(x) (x ## u)\n#define UINT64_C(x) __ESCAPE__(x ## ull)\n\n    /* 7.18.4.2 macros for greatest-width integer constants */\n#define INTMAX_C(x)  __ESCAPE__(x ## ll)\n#define UINTMAX_C(x) __ESCAPE__(x ## ull)\n\n#endif /* __STDC_CONSTANT_MACROS */\n\n    #ifdef __cplusplus\n         }  /* extern \"C\" */\n      }  /* namespace std */\n    #endif /* __cplusplus */\n  #endif /* __STDINT_DECLS */\n\n  #ifdef __cplusplus\n    #ifndef __STDINT_NO_EXPORTS\n      using ::std::int8_t;\n      using ::std::int16_t;\n      using ::std::int32_t;\n      using ::std::int64_t;\n      using ::std::uint8_t;\n      using ::std::uint16_t;\n      using ::std::uint32_t;\n      using ::std::uint64_t;\n      using ::std::int_least8_t;\n      using ::std::int_least16_t;\n      using ::std::int_least32_t;\n      using ::std::int_least64_t;\n      using ::std::uint_least8_t;\n      using ::std::uint_least16_t;\n      using ::std::uint_least32_t;\n      using ::std::uint_least64_t;\n      using ::std::int_fast8_t;\n      using ::std::int_fast16_t;\n      using ::std::int_fast32_t;\n      using ::std::int_fast64_t;\n      using ::std::uint_fast8_t;\n      using ::std::uint_fast16_t;\n      using ::std::uint_fast32_t;\n      using ::std::uint_fast64_t;\n      using ::std::intptr_t;\n      using ::std::uintptr_t;\n      using ::std::intmax_t;\n      using ::std::uintmax_t;\n    #endif \n  #endif /* __cplusplus */\n#endif\n\n#endif /* __c_stdint_h */\n\n/* end of c_stdint.h */\n\n\n\n"
  },
  {
    "path": "app/libc/c_stdio.c",
    "content": "#include \"c_stdio.h\"\n#include \"c_types.h\"\n// #include \"driver/uart.h\"\n\nint c_stdin = 999;\nint c_stdout = 1000;\nint c_stderr = 1001;\n\n\n/*\nFile: printf.c\n\nCopyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this list\nof conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or other\nmaterials provided with the distribution.\n\nNeither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its\ncontributors may be used to endorse or promote products derived from this software\nwithout specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\nIN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\nINDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\nOR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\nWHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\nOF SUCH DAMAGE.\n\n----------------------------------------------------------------------\n\nThis library is realy just two files: 'printf.h' and 'printf.c'.\n\nThey provide a simple and small (+200 loc) printf functionality to\nbe used in embedded systems.\n\nI've found them so usefull in debugging that I do not bother with a\ndebugger at all.\n\nThey are distributed in source form, so to use them, just compile them\ninto your project.\n\nTwo printf variants are provided: printf and sprintf.\n\nThe formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.\n\nZero padding and field width are also supported.\n\nIf the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the\nlong specifier is also\nsupported. Note that this will pull in some long math routines (pun intended!)\nand thus make your executable noticably longer.\n\nThe memory foot print of course depends on the target cpu, compiler and\ncompiler options, but a rough guestimate (based on a H8S target) is about\n1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.\nNot too bad. Your milage may vary. By hacking the source code you can\nget rid of some hunred bytes, I'm sure, but personally I feel the balance of\nfunctionality and flexibility versus  code size is close to optimal for\nmany embedded systems.\n\nTo use the printf you need to supply your own character output function,\nsomething like :\n\nvoid putc ( void* p, char c)\n    {\n    while (!SERIAL_PORT_EMPTY) ;\n    SERIAL_PORT_TX_REGISTER = c;\n    }\n\nBefore you can call printf you need to initialize it to use your\ncharacter output function with something like:\n\ninit_printf(NULL,putc);\n\nNotice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',\nthe NULL (or any pointer) you pass into the 'init_printf' will eventually be\npassed to your 'putc' routine. This allows you to pass some storage space (or\nanything realy) to the character output function, if necessary.\nThis is not often needed but it was implemented like that because it made\nimplementing the sprintf function so neat (look at the source code).\n\nThe code is re-entrant, except for the 'init_printf' function, so it\nis safe to call it from interupts too, although this may result in mixed output.\nIf you rely on re-entrancy, take care that your 'putc' function is re-entrant!\n\nThe printf and sprintf functions are actually macros that translate to\n'tfp_printf' and 'tfp_sprintf'. This makes it possible\nto use them along with 'stdio.h' printf's in a single source file.\nYou just need to undef the names before you include the 'stdio.h'.\nNote that these are not function like macros, so if you have variables\nor struct members with these names, things will explode in your face.\nWithout variadic macros this is the best we can do to wrap these\nfucnction. If it is a problem just give up the macros and use the\nfunctions directly or rename them.\n\nFor further details see source code.\n\nregs Kusti, 23.10.2004\n*/\n\n/*\nAdd lightweight %g support by vowstar, <vowstar@gmail.com>\nNodeMCU Team, 26.1.2015\n*/\n\ntypedef void (*putcf) (void *, char);\n\n#ifdef PRINTF_LONG_SUPPORT\n\nstatic int uli2a(unsigned long int num, unsigned int base, int uc, char *bf)\n{\n    int n = 0;\n    unsigned long int d = 1;\n    int len = 1;\n    while (num / d >= base)\n    {\n        d *= base;\n        len ++;\n    }\n    while (d != 0)\n    {\n        int dgt = num / d;\n        num %= d;\n        d /= base;\n        if (n || dgt > 0 || d == 0)\n        {\n            *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);\n            ++n;\n        }\n    }\n    *bf = 0;\n    return len;\n}\n\nstatic int li2a (long num, char *bf)\n{\n    int len = 0;\n    if (num < 0)\n    {\n        num = -num;\n        *bf++ = '-';\n        len ++;\n    }\n    len += uli2a(num, 10, 0, bf);\n    return len;\n}\n\n#endif\n\nstatic int ui2a(unsigned int num, unsigned int base, int uc, char *bf)\n{\n    int n = 0;\n    unsigned int d = 1;\n    int len = 1;\n    while (num / d >= base)\n    {\n        d *= base;\n        len ++;\n    }\n    while (d != 0)\n    {\n        int dgt = num / d;\n        num %= d;\n        d /= base;\n        if (n || dgt > 0 || d == 0)\n        {\n            *bf++ = dgt + (dgt < 10 ? '0' : (uc ? 'A' : 'a') - 10);\n            ++n;\n        }\n    }\n    *bf = 0;\n    return len;\n}\n\nstatic int i2a (int num, char *bf)\n{\n    int len = 0;\n    if (num < 0)\n    {\n        num = -num;\n        *bf++ = '-';\n        len ++;\n    }\n    len += ui2a(num, 10, 0, bf);\n    return len;\n}\n\n// Converts a floating point number to string.\nstatic int d2a(double num, char *bf)\n{\n    int len = 0;\n    double ipart = 0;\n    double fpart = 0;\n    double absnum = num;\n\n    // Add sign\n    if (absnum < 0)\n    {\n        absnum = -absnum;\n        *bf++ = '-';\n        // len must add 1 when return\n        // but can't add at here\n    }\n\n    // Extract integer part\n    ipart = (int)absnum;\n\n    // Extract floating part\n    fpart = absnum - (double)ipart;\n\n    // convert integer part to string\n#ifdef  PRINTF_LONG_SUPPORT\n    len += li2a(ipart, bf);\n#else\n    len += i2a(ipart, bf);\n#endif\n\n#ifndef EPSILON\n#define EPSILON ((double)(0.00000001))\n#endif\n    if (fpart < EPSILON)\n    {\n        // fpart is zero\n    }\n    else\n    {\n        bf += len;\n        // add dot\n        *bf ++ = '.';\n        len += 1;\n        // add zero after dot\n        while (fpart < 0.1)\n        {\n            fpart *= 10;\n            *bf ++ = '0';\n            len += 1;\n        }\n        while ((fpart < (double)1.0 / EPSILON) && ((fpart - (int)fpart) > EPSILON))\n        {\n            fpart = fpart * 10;\n        }\n#ifdef  PRINTF_LONG_SUPPORT\n        len += li2a((int)fpart, bf);\n#else\n        len += i2a((int)fpart, bf);\n#endif\n    }\n#undef EPSILON\n    if (num < 0)\n    {\n        len ++;\n    }\n    return len;\n}\n\nint a2d(char ch)\n{\n    if (ch >= '0' && ch <= '9')\n        return ch - '0';\n    else if (ch >= 'a' && ch <= 'f')\n        return ch - 'a' + 10;\n    else if (ch >= 'A' && ch <= 'F')\n        return ch - 'A' + 10;\n    else return -1;\n}\n\nchar a2i(char ch, char **src, int base, int *nump)\n{\n    char *p = *src;\n    int num = 0;\n    int digit;\n    while ((digit = a2d(ch)) >= 0)\n    {\n        if (digit > base) break;\n        num = num * base + digit;\n        ch = *p++;\n    }\n    *src = p;\n    *nump = num;\n    return ch;\n}\n\nstatic void putchw(void *putp, putcf putf, int n, char z, char *bf)\n{\n    char fc = z ? '0' : ' ';\n    char ch;\n    char *p = bf;\n    while (*p++ && n > 0)\n        n--;\n    while (n-- > 0)\n        putf(putp, fc);\n    while ((ch = *bf++))\n        putf(putp, ch);\n}\n\nvoid c_format(void *putp, putcf putf, char *fmt, va_list va)\n{\n    char bf[12];\n\n    char ch;\n\n\n    while ((ch = *(fmt++)))\n    {\n        if (ch != '%')\n            putf(putp, ch);\n        else\n        {\n            char lz = 0;\n#ifdef  PRINTF_LONG_SUPPORT\n            char lng = 0;\n#endif\n            int w = 0;\n            ch = *(fmt++);\n            if (ch == '0')\n            {\n                ch = *(fmt++);\n                lz = 1;\n            }\n            if (ch >= '0' && ch <= '9')\n            {\n                ch = a2i(ch, &fmt, 10, &w);\n            }\n#ifdef  PRINTF_LONG_SUPPORT\n            if (ch == 'l')\n            {\n                ch = *(fmt++);\n                lng = 1;\n            }\n#endif\n            switch (ch)\n            {\n            case 0:\n                goto abort;\n            case 'u' :\n            {\n#ifdef  PRINTF_LONG_SUPPORT\n                if (lng)\n                    uli2a(va_arg(va, unsigned long int), 10, 0, bf);\n                else\n#endif\n                    ui2a(va_arg(va, unsigned int), 10, 0, bf);\n                putchw(putp, putf, w, lz, bf);\n                break;\n            }\n            case 'o' :\n            {\n#ifdef  PRINTF_LONG_SUPPORT\n                if (lng)\n                    uli2a(va_arg(va, unsigned long int), 8, 0, bf);\n                else\n#endif\n                    ui2a(va_arg(va, unsigned int), 8, 0, bf);\n                putchw(putp, putf, w, lz, bf);\n                break;\n            }\n            case 'd' : case 'i':\n            {\n#ifdef  PRINTF_LONG_SUPPORT\n                if (lng)\n                    li2a(va_arg(va, unsigned long int), bf);\n                else\n#endif\n                    i2a(va_arg(va, int), bf);\n                putchw(putp, putf, w, lz, bf);\n                break;\n            }\n            case 'x': case 'X' :\n#ifdef  PRINTF_LONG_SUPPORT\n                if (lng)\n                    uli2a(va_arg(va, unsigned long int), 16, (ch == 'X'), bf);\n                else\n#endif\n                    ui2a(va_arg(va, unsigned int), 16, (ch == 'X'), bf);\n                putchw(putp, putf, w, lz, bf);\n                break;\n            case 'e':  case 'E': case 'f':\n            case 'g': case 'G':\n            {\n                d2a(va_arg(va, double), bf);\n                putchw(putp, putf, w, lz, bf);\n                break;\n            }\n            case 'c' :\n                putf(putp, (char)(va_arg(va, int)));\n                break;\n            case 's' :\n                putchw(putp, putf, w, 0, va_arg(va, char *));\n                break;\n            case '%' :\n                putf(putp, ch);\n            default:\n                break;\n            }\n        }\n    }\nabort:;\n}\n\n\nstatic void putcp(void *p, char c)\n{\n    *(*((char **)p))++ = c;\n}\n\n\nvoid c_sprintf(char *s, char *fmt, ...)\n{\n    va_list va;\n    va_start(va, fmt);\n    c_format(&s, putcp, fmt, va);\n    putcp(&s, 0);\n    va_end(va);\n}\n\nvoid nprintf(const char *s,size_t size)\n{\n    char str[2];\n    str[1]=0;\n\n    int i;\n    for(i=0;i<size;i++){\n        if(*s!=0)\n         {\n            str[0]=*s;\n            os_printf(\"%s\",str);\n            s++;\n         }\n         else\n            break;\n    }\n\n\n}\n\n\n"
  },
  {
    "path": "app/libc/c_stdio.h",
    "content": "#ifndef _C_STDIO_H_\n#define _C_STDIO_H_\n\n#define __need_size_t\n\n#include \"c_stddef.h\"\n#include \"osapi.h\"\n// #include \"driver/uart.h\"\n\n// #define __need___va_list\n//#include \"c_stdarg.h\"\n\n//struct __sFILE{\n//  int\t_r;\t\t/* read space left for getc() */\n//  int\t_w;\t\t/* write space left for putc() */\n//};\n// typedef struct __sFILE   __FILE;\n// typedef __FILE FILE;\n\nextern int c_stdin;\nextern int c_stdout;\nextern int c_stderr;\n\n// #define\t_IOFBF\t0\t\t/* setvbuf should set fully buffered */\n// #define\t_IOLBF\t1\t\t/* setvbuf should set line buffered */\n// #define\t_IONBF\t2\t\t/* setvbuf should set unbuffered */\n\n// #ifndef NULL\n// #define\tNULL\t0\n// #endif\n\n#define\tEOF\t(-1)\n\n#ifdef __BUFSIZ__\n#define   BUFSIZ         __BUFSIZ__\n#else\n#define   BUFSIZ         1024\n#endif\n\n#ifndef SEEK_SET\n#define\tSEEK_SET\t0\t/* set file offset to offset */\n#endif\n#ifndef SEEK_CUR\n#define\tSEEK_CUR\t1\t/* set file offset to current plus offset */\n#endif\n#ifndef SEEK_END\n#define\tSEEK_END\t2\t/* set file offset to EOF plus offset */\n#endif\n\n#define c_malloc(s) os_malloc(s)\n#define c_zalloc(s) os_zalloc(s)\n#define c_free(s) os_free(s)\n\nextern void output_redirect(const char *str);\n#define c_puts output_redirect\n\n// #define c_printf os_printf\n// int\tc_printf(const char *c, ...);\n#if defined( LUA_NUMBER_INTEGRAL )\n#define c_sprintf os_sprintf\n#else\n#include \"c_stdarg.h\"\nvoid c_sprintf(char* s,char *fmt, ...);\n#endif\n\n// #define c_vsprintf ets_vsprintf\n#define c_printf(...) do {\t\t\t\t\t\\\n\tunsigned char __print_buf[BUFSIZ];\t\t\\\n\tc_sprintf(__print_buf, __VA_ARGS__);\t\\\n\tc_puts(__print_buf);\t\t\t\t\t\\\n} while(0)\n\nvoid nprintf(const char *s,size_t size);\n\n\n\n// #define c_getc ets_getc\n// #define c_getchar ets_getc\n// note: contact esp to ensure the real getchar function..\n\n// FILE *c_fopen(const char *_name, const char *_type);\n// FILE *c_freopen(const char *, const char *, FILE *);\n// FILE *c_tmpfile(void);\n\n// int\tc_putchar(int);\n// int\tc_printf(const char *, ...);\n// int  c_sprintf(char *, const char *, ...);\n// int\tc_getc(FILE *);\n\n// int\tc_ungetc(int, FILE *);\n\n// int\tc_fprintf(FILE *, const char *, ...);\n// int\tc_fscanf(FILE *, const char *, ...);\n// int\tc_fclose(FILE *);\n// int\tc_fflush(FILE *);\n// int\tc_setvbuf(FILE *, char *, int, size_t);\n// void c_clearerr(FILE *);\n// int\tc_fseek(FILE *, long, int);\n// long c_ftell( FILE *);\n// int\tc_fputs(const char *, FILE *);\n// char *c_fgets(char *, int, FILE *);\n// size_t c_fread(void *, size_t _size, size_t _n, FILE *);\n// size_t c_fwrite(const void * , size_t _size, size_t _n, FILE *);\n// int\tc_feof(FILE *);\n// int\tc_ferror(FILE *);\n\n#endif /* _C_STDIO_H_ */\n"
  },
  {
    "path": "app/libc/c_stdlib.c",
    "content": "#include \"c_stdlib.h\"\n#include \"c_stdio.h\"\n#include \"c_types.h\"\n#include \"c_string.h\"\n#include \"user_interface.h\"\n\n\n\n// int c_abs(int x){\n// \treturn x>0?x:0-x;\n// }\n// void c_exit(int e){\n// }\n\n\n// make sure there is enough memory before real malloc, otherwise malloc will panic and reset\n// void *c_malloc(size_t __size){\n// \tif(__size>system_get_free_heap_size()){\n// \t\tNODE_ERR(\"malloc: not enough memory\\n\");\n// \t\treturn NULL;\n// \t}\n// \treturn (void *)os_malloc(__size);\n// }\n\n// void *c_zalloc(size_t __size){\n// \tif(__size>system_get_free_heap_size()){\n// \t\tNODE_ERR(\"zalloc: not enough memory\\n\");\n// \t\treturn NULL;\n// \t}\n// \treturn (void *)os_zalloc(__size);\n// }\n\n// void c_free(void *p){\n// \t// NODE_ERR(\"free1: %d\\n\", system_get_free_heap_size());\n// \tos_free(p);\n// \t// NODE_ERR(\"-free1: %d\\n\", system_get_free_heap_size());\n// }\n\n\n// int\tc_rand(void){\n// }\n// void c_srand(unsigned int __seed){\n// }\n\n// int\tc_atoi(const char *__nptr){\n// }\n#include <_ansi.h>\n//#include <reent.h>\n#include <string.h>\n//#include \"mprec.h\"\n\ndouble c_strtod(const char *string, char **endPtr) \n{\n\tint maxExponent = 511;\t/* Largest possible base 10 exponent.  Any\n\t\t\t\t * exponent larger than this will already\n\t\t\t\t * produce underflow or overflow, so there's\n\t\t\t\t * no need to worry about additional digits.\n\t\t\t\t */\n    double powersOf10[] = {\t/* Table giving binary powers of 10.  Entry */\n    10.,\t\t\t/* is 10^2^i.  Used to convert decimal */\n    100.,\t\t\t/* exponents into floating-point numbers. */\n    1.0e4,\n    1.0e8,\n    1.0e16,\n    1.0e32,\n    1.0e64,\n    1.0e128,\n    1.0e256\n    };\n    int sign, expSign = FALSE;\n    double fraction, dblExp, *d;\n    register const char *p;\n    register int c;\n    int exp = 0;\t\t/* Exponent read from \"EX\" field. */\n    int fracExp = 0;\t\t/* Exponent that derives from the fractional\n\t\t\t\t * part.  Under normal circumstatnces, it is\n\t\t\t\t * the negative of the number of digits in F.\n\t\t\t\t * However, if I is very long, the last digits\n\t\t\t\t * of I get dropped (otherwise a long I with a\n\t\t\t\t * large negative exponent could cause an\n\t\t\t\t * unnecessary overflow on I alone).  In this\n\t\t\t\t * case, fracExp is incremented one for each\n\t\t\t\t * dropped digit. */\n    int mantSize;\t\t/* Number of digits in mantissa. */\n    int decPt;\t\t\t/* Number of mantissa digits BEFORE decimal\n\t\t\t\t * point. */\n    const char *pExp;\t\t/* Temporarily holds location of exponent\n\t\t\t\t * in string. */\n\n    /*\n     * Strip off leading blanks and check for a sign.\n     */\n\n    p = string;\n    while (isspace((unsigned char)(*p))) {\n\tp += 1;\n    }\n    if (*p == '-') {\n\tsign = TRUE;\n\tp += 1;\n    } else {\n\tif (*p == '+') {\n\t    p += 1;\n\t}\n\tsign = FALSE;\n    }\n\n    /*\n     * Count the number of digits in the mantissa (including the decimal\n     * point), and also locate the decimal point.\n     */\n\n    decPt = -1;\n    for (mantSize = 0; ; mantSize += 1)\n    {\n\tc = *p;\n\tif (!isdigit(c)) {\n\t    if ((c != '.') || (decPt >= 0)) {\n\t\tbreak;\n\t    }\n\t    decPt = mantSize;\n\t}\n\tp += 1;\n    }\n\n    /*\n     * Now suck up the digits in the mantissa.  Use two integers to\n     * collect 9 digits each (this is faster than using floating-point).\n     * If the mantissa has more than 18 digits, ignore the extras, since\n     * they can't affect the value anyway.\n     */\n    \n    pExp  = p;\n    p -= mantSize;\n    if (decPt < 0) {\n\tdecPt = mantSize;\n    } else {\n\tmantSize -= 1;\t\t\t/* One of the digits was the point. */\n    }\n    if (mantSize > 18) {\n\tfracExp = decPt - 18;\n\tmantSize = 18;\n    } else {\n\tfracExp = decPt - mantSize;\n    }\n    if (mantSize == 0) {\n\tfraction = 0.0;\n\tp = string;\n\tgoto done;\n    } else {\n\tint frac1, frac2;\n\tfrac1 = 0;\n\tfor ( ; mantSize > 9; mantSize -= 1)\n\t{\n\t    c = *p;\n\t    p += 1;\n\t    if (c == '.') {\n\t\tc = *p;\n\t\tp += 1;\n\t    }\n\t    frac1 = 10*frac1 + (c - '0');\n\t}\n\tfrac2 = 0;\n\tfor (; mantSize > 0; mantSize -= 1)\n\t{\n\t    c = *p;\n\t    p += 1;\n\t    if (c == '.') {\n\t\tc = *p;\n\t\tp += 1;\n\t    }\n\t    frac2 = 10*frac2 + (c - '0');\n\t}\n\tfraction = (1.0e9 * frac1) + frac2;\n    }\n\n    /*\n     * Skim off the exponent.\n     */\n\n    p = pExp;\n    if ((*p == 'E') || (*p == 'e')) {\n\tp += 1;\n\tif (*p == '-') {\n\t    expSign = TRUE;\n\t    p += 1;\n\t} else {\n\t    if (*p == '+') {\n\t\tp += 1;\n\t    }\n\t    expSign = FALSE;\n\t}\n\tif (!isdigit((unsigned char)(*p))) {\n\t    p = pExp;\n\t    goto done;\n\t}\n\twhile (isdigit((unsigned char)(*p))) {\n\t    exp = exp * 10 + (*p - '0');\n\t    p += 1;\n\t}\n    }\n    if (expSign) {\n\texp = fracExp - exp;\n    } else {\n\texp = fracExp + exp;\n    }\n\n    /*\n     * Generate a floating-point number that represents the exponent.\n     * Do this by processing the exponent one bit at a time to combine\n     * many powers of 2 of 10. Then combine the exponent with the\n     * fraction.\n     */\n    \n    if (exp < 0) {\n\texpSign = TRUE;\n\texp = -exp;\n    } else {\n\texpSign = FALSE;\n    }\n    if (exp > maxExponent) {\n\texp = maxExponent;\n\t// errno = ERANGE;\n    }\n    dblExp = 1.0;\n    for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {\n\tif (exp & 01) {\n\t    dblExp *= *d;\n\t}\n    }\n    if (expSign) {\n\tfraction /= dblExp;\n    } else {\n\tfraction *= dblExp;\n    }\n\ndone:\n    if (endPtr != NULL) {\n\t*endPtr = (char *) p;\n    }\n\n    if (sign) {\n\treturn -fraction;\n    }\n    return fraction;\n}\n\n// long\tc_strtol(const char *__n, char **__end_PTR, int __base){\n// }\n// unsigned long c_strtoul(const char *__n, char **__end_PTR, int __base){\n// }\n// long long c_strtoll(const char *__n, char **__end_PTR, int __base){\n// }\n"
  },
  {
    "path": "app/libc/c_stdlib.h",
    "content": "/*\n * c_stdlib.h\n *\n * Definitions for common types, variables, and functions.\n */\n\n#ifndef _C_STDLIB_H_\n#define _C_STDLIB_H_\n\n#include \"c_stddef.h\"\n#include \"mem.h\"\n\n#define EXIT_FAILURE 1\n#define EXIT_SUCCESS 0\n\n#define __INT_MAX__ 2147483647\n#undef __RAND_MAX\n#if __INT_MAX__ == 32767\n#define __RAND_MAX 32767\n#else\n#define __RAND_MAX 0x7fffffff\n#endif\n#define RAND_MAX __RAND_MAX\n\n#ifndef mem_realloc\n#define mem_realloc pvPortRealloc\n#endif\n#ifndef os_realloc\n#define os_realloc(p, s) mem_realloc((p), (s))\n#endif\n\n// #define c_free os_free\n// #define c_malloc os_malloc\n// #define c_zalloc os_zalloc\n#define c_realloc os_realloc\n\n#define c_abs\tabs\n#define c_atoi\tatoi\n//#define c_strtod\tstrtod\n#define c_strtol\tstrtol\n#define c_strtoul\tstrtoul\n\n// int c_abs(int);\n\n// void c_exit(int);\n\n// c_getenv() get env \"LUA_INIT\" string for lua initialization.\nconst char *c_getenv(const char *__string);\n\n// int\tc_rand(void);\n// void c_srand(unsigned int __seed);\n\n// int\tc_atoi(const char *__nptr);\ndouble\tc_strtod(const char *__n, char **__end_PTR);\n// // long\tc_strtol(const char *__n, char **__end_PTR, int __base);\n// unsigned long c_strtoul(const char *__n, char **__end_PTR, int __base);\n// // long long c_strtoll(const char *__n, char **__end_PTR, int __base);\n\n#endif /* _C_STDLIB_H_ */\n"
  },
  {
    "path": "app/libc/c_string.c",
    "content": "#include \"c_string.h\"\n\nchar* itoa(int i, char b[])  // Convert Integer to ASCII!!\n{\n    char const digit[] = \"0123456789\";\n    char* p = b;\n    if(i<0){\n        *p++ = '-';\n        i *= -1;\n    }\n    int shifter = i;\n    do{ //Move to where representation ends\n        ++p;\n        shifter = shifter/10;\n    }while(shifter);\n    *p = '\\0';\n    do{ //Move back, inserting digits as u go\n        *--p = digit[i%10];\n        i = i/10;\n    }while(i);\n    return b;\n}\n\nchar * os_strcati(char *dest,int i){\n\n\tchar * p = dest;\n\twhile(*p!='\\0') p++;\n\n\titoa(i,p);\n\t\n\tp++;\n\t*p='\\0';\n\t\n    return dest;\n}\n\n// #define _tolower(__c) ((unsigned char)(__c) - 'A' + 'a')\n// #define _toupper(__c) ((unsigned char)(__c) - 'a' + 'A')\n\n// int tolower(int c){\n\n//     if(isupper(c))\n//         return _tolower(c);\n//     else\n//         return c;\n\n// }\n\nint os_strcasecmp(const char *s1, const char *s2)\n{\n    while (tolower(*s1++) == tolower(*s2++))\n    {\n        if (*s1 == '\\0')\n        {\n            return 0;\n        }\n    }\n\n    return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1);\n}\n\n// const char *c_strstr(const char * __s1, const char * __s2){\n// }\n\n// char *c_strncat(char * s1, const char * s2, size_t n){\n// }\n\n// size_t c_strcspn(const char * s1, const char * s2){\n// }\n\n// const char *c_strpbrk(const char * s1, const char * s2){\n// }\n\n// int c_strcoll(const char * s1, const char * s2){\n// }\n\n"
  },
  {
    "path": "app/libc/c_string.h",
    "content": "/*\n * c_string.h\n *\n * Definitions for memory and string functions.\n */\n\n#ifndef _C_STRING_H_\n#define\t_C_STRING_H_\n#include \"c_stddef.h\"\n#include \"osapi.h\"\n\n#ifndef NULL\n#define NULL 0\n#endif\n\n#define c_memcmp os_memcmp\n#define c_memcpy os_memcpy\n#define c_memset os_memset\n\n#define c_strcat os_strcat\n#define c_strchr os_strchr\n#define c_strcmp os_strcmp\n#define c_strcpy os_strcpy\n#define c_strlen os_strlen\n#define c_strncmp os_strncmp\n#define c_strncpy os_strncpy\n// #define c_strstr os_strstr\n#define c_strncasecmp c_strcmp\n\n#define c_strstr strstr\n#define c_strncat strncat\n#define c_strcspn strcspn\n#define c_strpbrk strpbrk\n#define c_strcoll strcoll\n#define c_strrchr strrchr\n\n\n\nchar* itoa(int i, char b[]);  // Convert Integer to ASCII!!\nchar * os_strcati(char *dest,int i);\n\nint os_strcasecmp(const char *s1, const char *s2);\n\n// const char *c_strstr(const char * __s1, const char * __s2);\n// char *c_strncat(char * __restrict /*s1*/, const char * __restrict /*s2*/, size_t n);\n// size_t c_strcspn(const char * s1, const char * s2);\n// const char *c_strpbrk(const char * /*s1*/, const char * /*s2*/);\n// int c_strcoll(const char * /*s1*/, const char * /*s2*/);\n\n\n\n#endif /* _C_STRING_H_ */\n"
  },
  {
    "path": "app/lwip/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nUP_EXTRACT_DIR = ..\nGEN_LIBS = liblwip.a\nCOMPONENTS_liblwip = api/liblwipapi.a\t\\\n\t\t\t\t\t\tapp/liblwipapp.a\t\\\n\t\t\t\t\t\tcore/liblwipcore.a\t\\\n\t\t\t\t\t\tcore/ipv4/liblwipipv4.a\t\\\n\t\t\t\t\t\tnetif/liblwipnetif.a\nendif\n\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/lwip/api/Makefile",
    "content": "\r\n#############################################################\r\n# Required variables for each makefile\r\n# Discard this section from all parent makefiles\r\n# Expected variables (with automatic defaults):\r\n#   CSRCS (all \"C\" files in the dir)\r\n#   SUBDIRS (all subdirs with a Makefile)\r\n#   GEN_LIBS - list of libs to be generated ()\r\n#   GEN_IMAGES - list of images to be generated ()\r\n#   COMPONENTS_xxx - a list of libs/objs in the form\r\n#     subdir/lib to be extracted and rolled up into\r\n#     a generated lib/image xxx.a ()\r\n#\r\nifndef PDIR\r\n\r\nGEN_LIBS = liblwipapi.a\r\n\r\nendif\r\n\r\n\r\n#############################################################\r\n# Configuration i.e. compile options etc.\r\n# Target specific stuff (defines etc.) goes in here!\r\n# Generally values applying to a tree are captured in the\r\n#   makefile at its root level - these are then overridden\r\n#   for a subtree within the makefile rooted therein\r\n#\r\n#DEFINES += \r\n\r\n#############################################################\r\n# Recursion Magic - Don't touch this!!\r\n#\r\n# Each subtree potentially has an include directory\r\n#   corresponding to the common APIs applicable to modules\r\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\r\n#   of a module can only contain the include directories up\r\n#   its parent path, and not its siblings\r\n#\r\n# Required for each makefile to inherit from the parent\r\n#\r\n\r\nINCLUDES := $(INCLUDES) -I $(PDIR)include\r\nINCLUDES += -I ./\r\nPDIR := ../$(PDIR)\r\nsinclude $(PDIR)Makefile\r\n\r\n"
  },
  {
    "path": "app/lwip/api/api_lib.c",
    "content": "/**\n * @file\n * Sequential API External module\n *\n */\n \n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n/* This is the part of the API that is linked with\n   the application */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/api.h\"\n#include \"lwip/tcpip.h\"\n#include \"lwip/memp.h\"\n\n#include \"lwip/ip.h\"\n#include \"lwip/raw.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/tcp.h\"\n\n#include <string.h>\n\n/**\n * Create a new netconn (of a specific type) that has a callback function.\n * The corresponding pcb is also created.\n *\n * @param t the type of 'connection' to create (@see enum netconn_type)\n * @param proto the IP protocol for RAW IP pcbs\n * @param callback a function to call on status changes (RX available, TX'ed)\n * @return a newly allocated struct netconn or\n *         NULL on memory error\n */\nstruct netconn*\nnetconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)\n{\n  struct netconn *conn;\n  struct api_msg msg;\n\n  conn = netconn_alloc(t, callback);\n  if (conn != NULL) {\n    msg.function = do_newconn;\n    msg.msg.msg.n.proto = proto;\n    msg.msg.conn = conn;\n    if (TCPIP_APIMSG(&msg) != ERR_OK) {\n      LWIP_ASSERT(\"freeing conn without freeing pcb\", conn->pcb.tcp == NULL);\n      LWIP_ASSERT(\"conn has no op_completed\", sys_sem_valid(&conn->op_completed));\n      LWIP_ASSERT(\"conn has no recvmbox\", sys_mbox_valid(&conn->recvmbox));\n#if LWIP_TCP\n      LWIP_ASSERT(\"conn->acceptmbox shouldn't exist\", !sys_mbox_valid(&conn->acceptmbox));\n#endif /* LWIP_TCP */\n      sys_sem_free(&conn->op_completed);\n      sys_mbox_free(&conn->recvmbox);\n      memp_free(MEMP_NETCONN, conn);\n      return NULL;\n    }\n  }\n  return conn;\n}\n\n/**\n * Close a netconn 'connection' and free its resources.\n * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate\n * after this returns.\n *\n * @param conn the netconn to delete\n * @return ERR_OK if the connection was deleted\n */\nerr_t\nnetconn_delete(struct netconn *conn)\n{\n  struct api_msg msg;\n\n  /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */\n  if (conn == NULL) {\n    return ERR_OK;\n  }\n\n  msg.function = do_delconn;\n  msg.msg.conn = conn;\n  tcpip_apimsg(&msg);\n\n  netconn_free(conn);\n\n  /* don't care for return value of do_delconn since it only calls void functions */\n\n  return ERR_OK;\n}\n\n/**\n * Get the local or remote IP address and port of a netconn.\n * For RAW netconns, this returns the protocol instead of a port!\n *\n * @param conn the netconn to query\n * @param addr a pointer to which to save the IP address\n * @param port a pointer to which to save the port (or protocol for RAW)\n * @param local 1 to get the local IP address, 0 to get the remote one\n * @return ERR_CONN for invalid connections\n *         ERR_OK if the information was retrieved\n */\nerr_t\nnetconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)\n{\n  struct api_msg msg;\n  err_t err;\n\n  LWIP_ERROR(\"netconn_getaddr: invalid conn\", (conn != NULL), return ERR_ARG;);\n  LWIP_ERROR(\"netconn_getaddr: invalid addr\", (addr != NULL), return ERR_ARG;);\n  LWIP_ERROR(\"netconn_getaddr: invalid port\", (port != NULL), return ERR_ARG;);\n\n  msg.function = do_getaddr;\n  msg.msg.conn = conn;\n  msg.msg.msg.ad.ipaddr = addr;\n  msg.msg.msg.ad.port = port;\n  msg.msg.msg.ad.local = local;\n  err = TCPIP_APIMSG(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n}\n\n/**\n * Bind a netconn to a specific local IP address and port.\n * Binding one netconn twice might not always be checked correctly!\n *\n * @param conn the netconn to bind\n * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY\n *             to bind to all addresses)\n * @param port the local port to bind the netconn to (not used for RAW)\n * @return ERR_OK if bound, any other err_t on failure\n */\nerr_t\nnetconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)\n{\n  struct api_msg msg;\n  err_t err;\n\n  LWIP_ERROR(\"netconn_bind: invalid conn\", (conn != NULL), return ERR_ARG;);\n\n  msg.function = do_bind;\n  msg.msg.conn = conn;\n  msg.msg.msg.bc.ipaddr = addr;\n  msg.msg.msg.bc.port = port;\n  err = TCPIP_APIMSG(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n}\n\n/**\n * Connect a netconn to a specific remote IP address and port.\n *\n * @param conn the netconn to connect\n * @param addr the remote IP address to connect to\n * @param port the remote port to connect to (no used for RAW)\n * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise\n */\nerr_t\nnetconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)\n{\n  struct api_msg msg;\n  err_t err;\n\n  LWIP_ERROR(\"netconn_connect: invalid conn\", (conn != NULL), return ERR_ARG;);\n\n  msg.function = do_connect;\n  msg.msg.conn = conn;\n  msg.msg.msg.bc.ipaddr = addr;\n  msg.msg.msg.bc.port = port;\n  /* This is the only function which need to not block tcpip_thread */\n  err = tcpip_apimsg(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n}\n\n/**\n * Disconnect a netconn from its current peer (only valid for UDP netconns).\n *\n * @param conn the netconn to disconnect\n * @return TODO: return value is not set here...\n */\nerr_t\nnetconn_disconnect(struct netconn *conn)\n{\n  struct api_msg msg;\n  err_t err;\n\n  LWIP_ERROR(\"netconn_disconnect: invalid conn\", (conn != NULL), return ERR_ARG;);\n\n  msg.function = do_disconnect;\n  msg.msg.conn = conn;\n  err = TCPIP_APIMSG(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n}\n\n/**\n * Set a TCP netconn into listen mode\n *\n * @param conn the tcp netconn to set to listen mode\n * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1\n * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns\n *         don't return any error (yet?))\n */\nerr_t\nnetconn_listen_with_backlog(struct netconn *conn, u8_t backlog)\n{\n#if LWIP_TCP\n  struct api_msg msg;\n  err_t err;\n\n  /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */\n  LWIP_UNUSED_ARG(backlog);\n\n  LWIP_ERROR(\"netconn_listen: invalid conn\", (conn != NULL), return ERR_ARG;);\n\n  msg.function = do_listen;\n  msg.msg.conn = conn;\n#if TCP_LISTEN_BACKLOG\n  msg.msg.msg.lb.backlog = backlog;\n#endif /* TCP_LISTEN_BACKLOG */\n  err = TCPIP_APIMSG(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n#else /* LWIP_TCP */\n  LWIP_UNUSED_ARG(conn);\n  LWIP_UNUSED_ARG(backlog);\n  return ERR_ARG;\n#endif /* LWIP_TCP */\n}\n\n/**\n * Accept a new connection on a TCP listening netconn.\n *\n * @param conn the TCP listen netconn\n * @param new_conn pointer where the new connection is stored\n * @return ERR_OK if a new connection has been received or an error\n *                code otherwise\n */\nerr_t\nnetconn_accept(struct netconn *conn, struct netconn **new_conn)\n{\n#if LWIP_TCP\n  struct netconn *newconn;\n  err_t err;\n#if TCP_LISTEN_BACKLOG\n  struct api_msg msg;\n#endif /* TCP_LISTEN_BACKLOG */\n\n  LWIP_ERROR(\"netconn_accept: invalid pointer\",    (new_conn != NULL),                  return ERR_ARG;);\n  *new_conn = NULL;\n  LWIP_ERROR(\"netconn_accept: invalid conn\",       (conn != NULL),                      return ERR_ARG;);\n  LWIP_ERROR(\"netconn_accept: invalid acceptmbox\", sys_mbox_valid(&conn->acceptmbox),   return ERR_ARG;);\n\n  err = conn->last_err;\n  if (ERR_IS_FATAL(err)) {\n    /* don't recv on fatal errors: this might block the application task\n       waiting on acceptmbox forever! */\n    return err;\n  }\n\n#if LWIP_SO_RCVTIMEO\n  if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {\n    NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);\n    return ERR_TIMEOUT;\n  }\n#else\n  sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);\n#endif /* LWIP_SO_RCVTIMEO*/\n  /* Register event with callback */\n  API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);\n\n  if (newconn == NULL) {\n    /* connection has been closed */\n    NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);\n    return ERR_CLSD;\n  }\n#if TCP_LISTEN_BACKLOG\n  /* Let the stack know that we have accepted the connection. */\n  msg.function = do_recv;\n  msg.msg.conn = conn;\n  /* don't care for the return value of do_recv */\n  TCPIP_APIMSG(&msg);\n#endif /* TCP_LISTEN_BACKLOG */\n\n  *new_conn = newconn;\n  /* don't set conn->last_err: it's only ERR_OK, anyway */\n  return ERR_OK;\n#else /* LWIP_TCP */\n  LWIP_UNUSED_ARG(conn);\n  LWIP_UNUSED_ARG(new_conn);\n  return ERR_ARG;\n#endif /* LWIP_TCP */\n}\n\n/**\n * Receive data: actual implementation that doesn't care whether pbuf or netbuf\n * is received\n *\n * @param conn the netconn from which to receive data\n * @param new_buf pointer where a new pbuf/netbuf is stored when received data\n * @return ERR_OK if data has been received, an error code otherwise (timeout,\n *                memory error or another error)\n */\nstatic err_t\nnetconn_recv_data(struct netconn *conn, void **new_buf)\n{\n  void *buf = NULL;\n  u16_t len;\n  err_t err;\n#if LWIP_TCP\n  struct api_msg msg;\n#endif /* LWIP_TCP */\n\n  LWIP_ERROR(\"netconn_recv: invalid pointer\", (new_buf != NULL), return ERR_ARG;);\n  *new_buf = NULL;\n  LWIP_ERROR(\"netconn_recv: invalid conn\",    (conn != NULL),    return ERR_ARG;);\n  LWIP_ERROR(\"netconn_accept: invalid recvmbox\", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);\n\n  err = conn->last_err;\n  if (ERR_IS_FATAL(err)) {\n    /* don't recv on fatal errors: this might block the application task\n       waiting on recvmbox forever! */\n    /* @todo: this does not allow us to fetch data that has been put into recvmbox\n       before the fatal error occurred - is that a problem? */\n    return err;\n  }\n\n#if LWIP_SO_RCVTIMEO\n  if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {\n    NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);\n    return ERR_TIMEOUT;\n  }\n#else\n  sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);\n#endif /* LWIP_SO_RCVTIMEO*/\n\n#if LWIP_TCP\n  if (conn->type == NETCONN_TCP) {\n    if (!netconn_get_noautorecved(conn) || (buf == NULL)) {\n      /* Let the stack know that we have taken the data. */\n      /* TODO: Speedup: Don't block and wait for the answer here\n         (to prevent multiple thread-switches). */\n      msg.function = do_recv;\n      msg.msg.conn = conn;\n      if (buf != NULL) {\n        msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;\n      } else {\n        msg.msg.msg.r.len = 1;\n      }\n      /* don't care for the return value of do_recv */\n      TCPIP_APIMSG(&msg);\n    }\n\n    /* If we are closed, we indicate that we no longer wish to use the socket */\n    if (buf == NULL) {\n      API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);\n      /* Avoid to lose any previous error code */\n      NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);\n      return ERR_CLSD;\n    }\n    len = ((struct pbuf *)buf)->tot_len;\n  }\n#endif /* LWIP_TCP */\n#if LWIP_TCP && (LWIP_UDP || LWIP_RAW)\n  else\n#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */\n#if (LWIP_UDP || LWIP_RAW)\n  {\n    LWIP_ASSERT(\"buf != NULL\", buf != NULL);\n    len = netbuf_len((struct netbuf *)buf);\n  }\n#endif /* (LWIP_UDP || LWIP_RAW) */\n\n#if LWIP_SO_RCVBUF\n  SYS_ARCH_DEC(conn->recv_avail, len);\n#endif /* LWIP_SO_RCVBUF */\n  /* Register event with callback */\n  API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);\n\n  LWIP_DEBUGF(API_LIB_DEBUG, (\"netconn_recv_data: received %p, len=%\"U16_F\"\\n\", buf, len));\n\n  *new_buf = buf;\n  /* don't set conn->last_err: it's only ERR_OK, anyway */\n  return ERR_OK;\n}\n\n/**\n * Receive data (in form of a pbuf) from a TCP netconn\n *\n * @param conn the netconn from which to receive data\n * @param new_buf pointer where a new pbuf is stored when received data\n * @return ERR_OK if data has been received, an error code otherwise (timeout,\n *                memory error or another error)\n *         ERR_ARG if conn is not a TCP netconn\n */\nerr_t\nnetconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)\n{\n  LWIP_ERROR(\"netconn_recv: invalid conn\", (conn != NULL) &&\n             netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);\n\n  return netconn_recv_data(conn, (void **)new_buf);\n}\n\n/**\n * Receive data (in form of a netbuf containing a packet buffer) from a netconn\n *\n * @param conn the netconn from which to receive data\n * @param new_buf pointer where a new netbuf is stored when received data\n * @return ERR_OK if data has been received, an error code otherwise (timeout,\n *                memory error or another error)\n */\nerr_t\nnetconn_recv(struct netconn *conn, struct netbuf **new_buf)\n{\n#if LWIP_TCP\n  struct netbuf *buf = NULL;\n  err_t err;\n#endif /* LWIP_TCP */\n\n  LWIP_ERROR(\"netconn_recv: invalid pointer\", (new_buf != NULL), return ERR_ARG;);\n  *new_buf = NULL;\n  LWIP_ERROR(\"netconn_recv: invalid conn\",    (conn != NULL),    return ERR_ARG;);\n  LWIP_ERROR(\"netconn_accept: invalid recvmbox\", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);\n\n#if LWIP_TCP\n  if (conn->type == NETCONN_TCP) {\n    struct pbuf *p = NULL;\n    /* This is not a listening netconn, since recvmbox is set */\n\n    buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);\n    if (buf == NULL) {\n      NETCONN_SET_SAFE_ERR(conn, ERR_MEM);\n      return ERR_MEM;\n    }\n\n    err = netconn_recv_data(conn, (void **)&p);\n    if (err != ERR_OK) {\n      memp_free(MEMP_NETBUF, buf);\n      return err;\n    }\n    LWIP_ASSERT(\"p != NULL\", p != NULL);\n\n    buf->p = p;\n    buf->ptr = p;\n    buf->port = 0;\n    ip_addr_set_any(&buf->addr);\n    *new_buf = buf;\n    /* don't set conn->last_err: it's only ERR_OK, anyway */\n    return ERR_OK;\n  } else\n#endif /* LWIP_TCP */\n  {\n#if (LWIP_UDP || LWIP_RAW)\n    return netconn_recv_data(conn, (void **)new_buf);\n#endif /* (LWIP_UDP || LWIP_RAW) */\n  }\n}\n\n/**\n * TCP: update the receive window: by calling this, the application\n * tells the stack that it has processed data and is able to accept\n * new data.\n * ATTENTION: use with care, this is mainly used for sockets!\n * Can only be used when calling netconn_set_noautorecved(conn, 1) before.\n *\n * @param conn the netconn for which to update the receive window\n * @param length amount of data processed (ATTENTION: this must be accurate!)\n */\nvoid\nnetconn_recved(struct netconn *conn, u32_t length)\n{\n#if LWIP_TCP\n  if ((conn != NULL) && (conn->type == NETCONN_TCP) &&\n      (netconn_get_noautorecved(conn))) {\n    struct api_msg msg;\n    /* Let the stack know that we have taken the data. */\n    /* TODO: Speedup: Don't block and wait for the answer here\n       (to prevent multiple thread-switches). */\n    msg.function = do_recv;\n    msg.msg.conn = conn;\n    msg.msg.msg.r.len = length;\n    /* don't care for the return value of do_recv */\n    TCPIP_APIMSG(&msg);\n  }\n#else /* LWIP_TCP */\n  LWIP_UNUSED_ARG(conn);\n  LWIP_UNUSED_ARG(length);\n#endif /* LWIP_TCP */\n}\n\n/**\n * Send data (in form of a netbuf) to a specific remote IP address and port.\n * Only to be used for UDP and RAW netconns (not TCP).\n *\n * @param conn the netconn over which to send data\n * @param buf a netbuf containing the data to send\n * @param addr the remote IP address to which to send the data\n * @param port the remote port to which to send the data\n * @return ERR_OK if data was sent, any other err_t on error\n */\nerr_t\nnetconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)\n{\n  if (buf != NULL) {\n    ip_addr_set(&buf->addr, addr);\n    buf->port = port;\n    return netconn_send(conn, buf);\n  }\n  return ERR_VAL;\n}\n\n/**\n * Send data over a UDP or RAW netconn (that is already connected).\n *\n * @param conn the UDP or RAW netconn over which to send data\n * @param buf a netbuf containing the data to send\n * @return ERR_OK if data was sent, any other err_t on error\n */\nerr_t\nnetconn_send(struct netconn *conn, struct netbuf *buf)\n{\n  struct api_msg msg;\n  err_t err;\n\n  LWIP_ERROR(\"netconn_send: invalid conn\",  (conn != NULL), return ERR_ARG;);\n\n  LWIP_DEBUGF(API_LIB_DEBUG, (\"netconn_send: sending %\"U16_F\" bytes\\n\", buf->p->tot_len));\n  msg.function = do_send;\n  msg.msg.conn = conn;\n  msg.msg.msg.b = buf;\n  err = TCPIP_APIMSG(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n}\n\n/**\n * Send data over a TCP netconn.\n *\n * @param conn the TCP netconn over which to send data\n * @param dataptr pointer to the application buffer that contains the data to send\n * @param size size of the application data to send\n * @param apiflags combination of following flags :\n * - NETCONN_COPY: data will be copied into memory belonging to the stack\n * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent\n * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once\n * @return ERR_OK if data was sent, any other err_t on error\n */\nerr_t\nnetconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)\n{\n  struct api_msg msg;\n  err_t err;\n\n  LWIP_ERROR(\"netconn_write: invalid conn\",  (conn != NULL), return ERR_ARG;);\n  LWIP_ERROR(\"netconn_write: invalid conn->type\",  (conn->type == NETCONN_TCP), return ERR_VAL;);\n  if (size == 0) {\n    return ERR_OK;\n  }\n\n  /* @todo: for non-blocking write, check if 'size' would ever fit into\n            snd_queue or snd_buf */\n  msg.function = do_write;\n  msg.msg.conn = conn;\n  msg.msg.msg.w.dataptr = dataptr;\n  msg.msg.msg.w.apiflags = apiflags;\n  msg.msg.msg.w.len = size;\n  /* For locking the core: this _can_ be delayed on low memory/low send buffer,\n     but if it is, this is done inside api_msg.c:do_write(), so we can use the\n     non-blocking version here. */\n  err = TCPIP_APIMSG(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n}\n\n/**\n * Close ot shutdown a TCP netconn (doesn't delete it).\n *\n * @param conn the TCP netconn to close or shutdown\n * @param how fully close or only shutdown one side?\n * @return ERR_OK if the netconn was closed, any other err_t on error\n */\nstatic err_t\nnetconn_close_shutdown(struct netconn *conn, u8_t how)\n{\n  struct api_msg msg;\n  err_t err;\n\n  LWIP_ERROR(\"netconn_close: invalid conn\",  (conn != NULL), return ERR_ARG;);\n\n  msg.function = do_close;\n  msg.msg.conn = conn;\n  /* shutting down both ends is the same as closing */\n  msg.msg.msg.sd.shut = how;\n  /* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,\n     don't use TCPIP_APIMSG here */\n  err = tcpip_apimsg(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n}\n\n/**\n * Close a TCP netconn (doesn't delete it).\n *\n * @param conn the TCP netconn to close\n * @return ERR_OK if the netconn was closed, any other err_t on error\n */\nerr_t\nnetconn_close(struct netconn *conn)\n{\n  /* shutting down both ends is the same as closing */\n  return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);\n}\n\n/**\n * Shut down one or both sides of a TCP netconn (doesn't delete it).\n *\n * @param conn the TCP netconn to shut down\n * @return ERR_OK if the netconn was closed, any other err_t on error\n */\nerr_t\nnetconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)\n{\n  return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));\n}\n\n#if LWIP_IGMP\n/**\n * Join multicast groups for UDP netconns.\n *\n * @param conn the UDP netconn for which to change multicast addresses\n * @param multiaddr IP address of the multicast group to join or leave\n * @param netif_addr the IP address of the network interface on which to send\n *                  the igmp message\n * @param join_or_leave flag whether to send a join- or leave-message\n * @return ERR_OK if the action was taken, any err_t on error\n */\nerr_t\nnetconn_join_leave_group(struct netconn *conn,\n                         ip_addr_t *multiaddr,\n                         ip_addr_t *netif_addr,\n                         enum netconn_igmp join_or_leave)\n{\n  struct api_msg msg;\n  err_t err;\n\n  LWIP_ERROR(\"netconn_join_leave_group: invalid conn\",  (conn != NULL), return ERR_ARG;);\n\n  msg.function = do_join_leave_group;\n  msg.msg.conn = conn;\n  msg.msg.msg.jl.multiaddr = multiaddr;\n  msg.msg.msg.jl.netif_addr = netif_addr;\n  msg.msg.msg.jl.join_or_leave = join_or_leave;\n  err = TCPIP_APIMSG(&msg);\n\n  NETCONN_SET_SAFE_ERR(conn, err);\n  return err;\n}\n#endif /* LWIP_IGMP */\n\n#if LWIP_DNS\n/**\n * Execute a DNS query, only one IP address is returned\n *\n * @param name a string representation of the DNS host name to query\n * @param addr a preallocated ip_addr_t where to store the resolved IP address\n * @return ERR_OK: resolving succeeded\n *         ERR_MEM: memory error, try again later\n *         ERR_ARG: dns client not initialized or invalid hostname\n *         ERR_VAL: dns server response was invalid\n */\nerr_t\nnetconn_gethostbyname(const char *name, ip_addr_t *addr)\n{\n  struct dns_api_msg msg;\n  err_t err;\n  sys_sem_t sem;\n\n  LWIP_ERROR(\"netconn_gethostbyname: invalid name\", (name != NULL), return ERR_ARG;);\n  LWIP_ERROR(\"netconn_gethostbyname: invalid addr\", (addr != NULL), return ERR_ARG;);\n\n  err = sys_sem_new(&sem, 0);\n  if (err != ERR_OK) {\n    return err;\n  }\n\n  msg.name = name;\n  msg.addr = addr;\n  msg.err = &err;\n  msg.sem = &sem;\n\n  tcpip_callback(do_gethostbyname, &msg);\n  sys_sem_wait(&sem);\n  sys_sem_free(&sem);\n\n  return err;\n}\n#endif /* LWIP_DNS*/\n\n#endif /* LWIP_NETCONN */\n"
  },
  {
    "path": "app/lwip/api/api_msg.c",
    "content": "/**\n * @file\n * Sequential API Internal module\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/api_msg.h\"\n\n#include \"lwip/ip.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/tcp.h\"\n#include \"lwip/raw.h\"\n\n#include \"lwip/memp.h\"\n#include \"lwip/tcpip.h\"\n#include \"lwip/igmp.h\"\n#include \"lwip/dns.h\"\n\n#include <string.h>\n\n#define SET_NONBLOCKING_CONNECT(conn, val)  do { if(val) { \\\n  (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \\\n} else { \\\n  (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)\n#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)\n\n/* forward declarations */\n#if LWIP_TCP\nstatic err_t do_writemore(struct netconn *conn);\nstatic void do_close_internal(struct netconn *conn);\n#endif\n\n#if LWIP_RAW\n/**\n * Receive callback function for RAW netconns.\n * Doesn't 'eat' the packet, only references it and sends it to\n * conn->recvmbox\n *\n * @see raw.h (struct raw_pcb.recv) for parameters and return value\n */\nstatic u8_t\nrecv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,\n    ip_addr_t *addr)\n{\n  struct pbuf *q;\n  struct netbuf *buf;\n  struct netconn *conn;\n\n  LWIP_UNUSED_ARG(addr);\n  conn = (struct netconn *)arg;\n\n  if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {\n#if LWIP_SO_RCVBUF\n    int recv_avail;\n    SYS_ARCH_GET(conn->recv_avail, recv_avail);\n    if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {\n      return 0;\n    }\n#endif /* LWIP_SO_RCVBUF */\n    /* copy the whole packet into new pbufs */\n    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\n    if(q != NULL) {\n      if (pbuf_copy(q, p) != ERR_OK) {\n        pbuf_free(q);\n        q = NULL;\n      }\n    }\n\n    if (q != NULL) {\n      u16_t len;\n      buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);\n      if (buf == NULL) {\n        pbuf_free(q);\n        return 0;\n      }\n\n      buf->p = q;\n      buf->ptr = q;\n      ip_addr_copy(buf->addr, *ip_current_src_addr());\n      buf->port = pcb->protocol;\n\n      len = q->tot_len;\n      if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {\n        netbuf_delete(buf);\n        return 0;\n      } else {\n#if LWIP_SO_RCVBUF\n        SYS_ARCH_INC(conn->recv_avail, len);\n#endif /* LWIP_SO_RCVBUF */\n        /* Register event with callback */\n        API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);\n      }\n    }\n  }\n\n  return 0; /* do not eat the packet */\n}\n#endif /* LWIP_RAW*/\n\n#if LWIP_UDP\n/**\n * Receive callback function for UDP netconns.\n * Posts the packet to conn->recvmbox or deletes it on memory error.\n *\n * @see udp.h (struct udp_pcb.recv) for parameters\n */\nstatic void\nrecv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,\n   ip_addr_t *addr, u16_t port)\n{\n  struct netbuf *buf;\n  struct netconn *conn;\n  u16_t len;\n#if LWIP_SO_RCVBUF\n  int recv_avail;\n#endif /* LWIP_SO_RCVBUF */\n\n  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */\n  LWIP_ASSERT(\"recv_udp must have a pcb argument\", pcb != NULL);\n  LWIP_ASSERT(\"recv_udp must have an argument\", arg != NULL);\n  conn = (struct netconn *)arg;\n  LWIP_ASSERT(\"recv_udp: recv for wrong pcb!\", conn->pcb.udp == pcb);\n\n#if LWIP_SO_RCVBUF\n  SYS_ARCH_GET(conn->recv_avail, recv_avail);\n  if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||\n      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {\n#else  /* LWIP_SO_RCVBUF */\n  if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {\n#endif /* LWIP_SO_RCVBUF */\n    pbuf_free(p);\n    return;\n  }\n\n  buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);\n  if (buf == NULL) {\n    pbuf_free(p);\n    return;\n  } else {\n    buf->p = p;\n    buf->ptr = p;\n    ip_addr_set(&buf->addr, addr);\n    buf->port = port;\n#if LWIP_NETBUF_RECVINFO\n    {\n      const struct ip_hdr* iphdr = ip_current_header();\n      /* get the UDP header - always in the first pbuf, ensured by udp_input */\n      const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));\n#if LWIP_CHECKSUM_ON_COPY\n      buf->flags = NETBUF_FLAG_DESTADDR;\n#endif /* LWIP_CHECKSUM_ON_COPY */\n      ip_addr_set(&buf->toaddr, ip_current_dest_addr());\n      buf->toport_chksum = udphdr->dest;\n    }\n#endif /* LWIP_NETBUF_RECVINFO */\n  }\n\n  len = p->tot_len;\n  if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {\n    netbuf_delete(buf);\n    return;\n  } else {\n#if LWIP_SO_RCVBUF\n    SYS_ARCH_INC(conn->recv_avail, len);\n#endif /* LWIP_SO_RCVBUF */\n    /* Register event with callback */\n    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);\n  }\n}\n#endif /* LWIP_UDP */\n\n#if LWIP_TCP\n/**\n * Receive callback function for TCP netconns.\n * Posts the packet to conn->recvmbox, but doesn't delete it on errors.\n *\n * @see tcp.h (struct tcp_pcb.recv) for parameters and return value\n */\nstatic err_t\nrecv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\n{\n  struct netconn *conn;\n  u16_t len;\n\n  LWIP_UNUSED_ARG(pcb);\n  LWIP_ASSERT(\"recv_tcp must have a pcb argument\", pcb != NULL);\n  LWIP_ASSERT(\"recv_tcp must have an argument\", arg != NULL);\n  conn = (struct netconn *)arg;\n  LWIP_ASSERT(\"recv_tcp: recv for wrong pcb!\", conn->pcb.tcp == pcb);\n\n  if (conn == NULL) {\n    return ERR_VAL;\n  }\n  if (!sys_mbox_valid(&conn->recvmbox)) {\n    /* recvmbox already deleted */\n    if (p != NULL) {\n      tcp_recved(pcb, p->tot_len);\n      pbuf_free(p);\n    }\n    return ERR_OK;\n  }\n  /* Unlike for UDP or RAW pcbs, don't check for available space\n     using recv_avail since that could break the connection\n     (data is already ACKed) */\n\n  /* don't overwrite fatal errors! */\n  NETCONN_SET_SAFE_ERR(conn, err);\n\n  if (p != NULL) {\n    len = p->tot_len;\n  } else {\n    len = 0;\n  }\n\n  if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {\n    /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */\n    return ERR_MEM;\n  } else {\n#if LWIP_SO_RCVBUF\n    SYS_ARCH_INC(conn->recv_avail, len);\n#endif /* LWIP_SO_RCVBUF */\n    /* Register event with callback */\n    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);\n  }\n\n  return ERR_OK;\n}\n\n/**\n * Poll callback function for TCP netconns.\n * Wakes up an application thread that waits for a connection to close\n * or data to be sent. The application thread then takes the\n * appropriate action to go on.\n *\n * Signals the conn->sem.\n * netconn_close waits for conn->sem if closing failed.\n *\n * @see tcp.h (struct tcp_pcb.poll) for parameters and return value\n */\nstatic err_t\npoll_tcp(void *arg, struct tcp_pcb *pcb)\n{\n  struct netconn *conn = (struct netconn *)arg;\n\n  LWIP_UNUSED_ARG(pcb);\n  LWIP_ASSERT(\"conn != NULL\", (conn != NULL));\n\n  if (conn->state == NETCONN_WRITE) {\n    do_writemore(conn);\n  } else if (conn->state == NETCONN_CLOSE) {\n    do_close_internal(conn);\n  }\n  /* @todo: implement connect timeout here? */\n\n  /* Did a nonblocking write fail before? Then check available write-space. */\n  if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {\n    /* If the queued byte- or pbuf-count drops below the configured low-water limit,\n       let select mark this pcb as writable again. */\n    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&\n      (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {\n      conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;\n      API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);\n    }\n  }\n\n  return ERR_OK;\n}\n\n/**\n * Sent callback function for TCP netconns.\n * Signals the conn->sem and calls API_EVENT.\n * netconn_write waits for conn->sem if send buffer is low.\n *\n * @see tcp.h (struct tcp_pcb.sent) for parameters and return value\n */\nstatic err_t\nsent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)\n{\n  struct netconn *conn = (struct netconn *)arg;\n\n  LWIP_UNUSED_ARG(pcb);\n  LWIP_ASSERT(\"conn != NULL\", (conn != NULL));\n\n  if (conn->state == NETCONN_WRITE) {\n    do_writemore(conn);\n  } else if (conn->state == NETCONN_CLOSE) {\n    do_close_internal(conn);\n  }\n\n  if (conn) {\n    /* If the queued byte- or pbuf-count drops below the configured low-water limit,\n       let select mark this pcb as writable again. */\n    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&\n      (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {\n      conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;\n      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);\n    }\n  }\n  \n  return ERR_OK;\n}\n\n/**\n * Error callback function for TCP netconns.\n * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.\n * The application thread has then to decide what to do.\n *\n * @see tcp.h (struct tcp_pcb.err) for parameters\n */\nstatic void\nerr_tcp(void *arg, err_t err)\n{\n  struct netconn *conn;\n  enum netconn_state old_state;\n  SYS_ARCH_DECL_PROTECT(lev);\n\n  conn = (struct netconn *)arg;\n  LWIP_ASSERT(\"conn != NULL\", (conn != NULL));\n\n  conn->pcb.tcp = NULL;\n\n  /* no check since this is always fatal! */\n  SYS_ARCH_PROTECT(lev);\n  conn->last_err = err;\n  SYS_ARCH_UNPROTECT(lev);\n\n  /* reset conn->state now before waking up other threads */\n  old_state = conn->state;\n  conn->state = NETCONN_NONE;\n\n  /* Notify the user layer about a connection error. Used to signal\n     select. */\n  API_EVENT(conn, NETCONN_EVT_ERROR, 0);\n  /* Try to release selects pending on 'read' or 'write', too.\n     They will get an error if they actually try to read or write. */\n  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\n  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);\n\n  /* pass NULL-message to recvmbox to wake up pending recv */\n  if (sys_mbox_valid(&conn->recvmbox)) {\n    /* use trypost to prevent deadlock */\n    sys_mbox_trypost(&conn->recvmbox, NULL);\n  }\n  /* pass NULL-message to acceptmbox to wake up pending accept */\n  if (sys_mbox_valid(&conn->acceptmbox)) {\n    /* use trypost to preven deadlock */\n    sys_mbox_trypost(&conn->acceptmbox, NULL);\n  }\n\n  if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||\n      (old_state == NETCONN_CONNECT)) {\n    /* calling do_writemore/do_close_internal is not necessary\n       since the pcb has already been deleted! */\n    int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);\n    SET_NONBLOCKING_CONNECT(conn, 0);\n\n    if (!was_nonblocking_connect) {\n      /* set error return code */\n      LWIP_ASSERT(\"conn->current_msg != NULL\", conn->current_msg != NULL);\n      conn->current_msg->err = err;\n      conn->current_msg = NULL;\n      /* wake up the waiting task */\n      sys_sem_signal(&conn->op_completed);\n    }\n  } else {\n    LWIP_ASSERT(\"conn->current_msg == NULL\", conn->current_msg == NULL);\n  }\n}\n\n/**\n * Setup a tcp_pcb with the correct callback function pointers\n * and their arguments.\n *\n * @param conn the TCP netconn to setup\n */\nstatic void\nsetup_tcp(struct netconn *conn)\n{\n  struct tcp_pcb *pcb;\n\n  pcb = conn->pcb.tcp;\n  tcp_arg(pcb, conn);\n  tcp_recv(pcb, recv_tcp);\n  tcp_sent(pcb, sent_tcp);\n  tcp_poll(pcb, poll_tcp, 4);\n  tcp_err(pcb, err_tcp);\n}\n\n/**\n * Accept callback function for TCP netconns.\n * Allocates a new netconn and posts that to conn->acceptmbox.\n *\n * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value\n */\nstatic err_t\naccept_function(void *arg, struct tcp_pcb *newpcb, err_t err)\n{\n  struct netconn *newconn;\n  struct netconn *conn = (struct netconn *)arg;\n\n  LWIP_DEBUGF(API_MSG_DEBUG, (\"accept_function: newpcb->tate: %s\\n\", tcp_debug_state_str(newpcb->state)));\n\n  if (!sys_mbox_valid(&conn->acceptmbox)) {\n    LWIP_DEBUGF(API_MSG_DEBUG, (\"accept_function: acceptmbox already deleted\\n\"));\n    return ERR_VAL;\n  }\n\n  /* We have to set the callback here even though\n   * the new socket is unknown. conn->socket is marked as -1. */\n  newconn = netconn_alloc(conn->type, conn->callback);\n  if (newconn == NULL) {\n    return ERR_MEM;\n  }\n  newconn->pcb.tcp = newpcb;\n  setup_tcp(newconn);\n  /* no protection: when creating the pcb, the netconn is not yet known\n     to the application thread */\n  newconn->last_err = err;\n\n  if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {\n    /* When returning != ERR_OK, the pcb is aborted in tcp_process(),\n       so do nothing here! */\n    newconn->pcb.tcp = NULL;\n    /* no need to drain since we know the recvmbox is empty. */\n    sys_mbox_free(&newconn->recvmbox);\n    sys_mbox_set_invalid(&newconn->recvmbox);\n    netconn_free(newconn);\n    return ERR_MEM;\n  } else {\n    /* Register event with callback */\n    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\n  }\n\n  return ERR_OK;\n}\n#endif /* LWIP_TCP */\n\n/**\n * Create a new pcb of a specific type.\n * Called from do_newconn().\n *\n * @param msg the api_msg_msg describing the connection type\n * @return msg->conn->err, but the return value is currently ignored\n */\nstatic void\npcb_new(struct api_msg_msg *msg)\n{\n  LWIP_ASSERT(\"pcb_new: pcb already allocated\", msg->conn->pcb.tcp == NULL);\n\n  /* Allocate a PCB for this connection */\n  switch(NETCONNTYPE_GROUP(msg->conn->type)) {\n#if LWIP_RAW\n  case NETCONN_RAW:\n    msg->conn->pcb.raw = raw_new(msg->msg.n.proto);\n    if(msg->conn->pcb.raw == NULL) {\n      msg->err = ERR_MEM;\n      break;\n    }\n    raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);\n    break;\n#endif /* LWIP_RAW */\n#if LWIP_UDP\n  case NETCONN_UDP:\n    msg->conn->pcb.udp = udp_new();\n    if(msg->conn->pcb.udp == NULL) {\n      msg->err = ERR_MEM;\n      break;\n    }\n#if LWIP_UDPLITE\n    if (msg->conn->type==NETCONN_UDPLITE) {\n      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);\n    }\n#endif /* LWIP_UDPLITE */\n    if (msg->conn->type==NETCONN_UDPNOCHKSUM) {\n      udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);\n    }\n    udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\n    break;\n#endif /* LWIP_UDP */\n#if LWIP_TCP\n  case NETCONN_TCP:\n    msg->conn->pcb.tcp = tcp_new();\n    if(msg->conn->pcb.tcp == NULL) {\n      msg->err = ERR_MEM;\n      break;\n    }\n    setup_tcp(msg->conn);\n    break;\n#endif /* LWIP_TCP */\n  default:\n    /* Unsupported netconn type, e.g. protocol disabled */\n    msg->err = ERR_VAL;\n    break;\n  }\n}\n\n/**\n * Create a new pcb of a specific type inside a netconn.\n * Called from netconn_new_with_proto_and_callback.\n *\n * @param msg the api_msg_msg describing the connection type\n */\nvoid\ndo_newconn(struct api_msg_msg *msg)\n{\n  msg->err = ERR_OK;\n  if(msg->conn->pcb.tcp == NULL) {\n    pcb_new(msg);\n  }\n  /* Else? This \"new\" connection already has a PCB allocated. */\n  /* Is this an error condition? Should it be deleted? */\n  /* We currently just are happy and return. */\n\n  TCPIP_APIMSG_ACK(msg);\n}\n\n/**\n * Create a new netconn (of a specific type) that has a callback function.\n * The corresponding pcb is NOT created!\n *\n * @param t the type of 'connection' to create (@see enum netconn_type)\n * @param proto the IP protocol for RAW IP pcbs\n * @param callback a function to call on status changes (RX available, TX'ed)\n * @return a newly allocated struct netconn or\n *         NULL on memory error\n */\nstruct netconn*\nnetconn_alloc(enum netconn_type t, netconn_callback callback)\n{\n  struct netconn *conn;\n  int size;\n\n  conn = (struct netconn *)memp_malloc(MEMP_NETCONN);\n  if (conn == NULL) {\n    return NULL;\n  }\n\n  conn->last_err = ERR_OK;\n  conn->type = t;\n  conn->pcb.tcp = NULL;\n\n#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \\\n    (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)\n  size = DEFAULT_RAW_RECVMBOX_SIZE;\n#else\n  switch(NETCONNTYPE_GROUP(t)) {\n#if LWIP_RAW\n  case NETCONN_RAW:\n    size = DEFAULT_RAW_RECVMBOX_SIZE;\n    break;\n#endif /* LWIP_RAW */\n#if LWIP_UDP\n  case NETCONN_UDP:\n    size = DEFAULT_UDP_RECVMBOX_SIZE;\n    break;\n#endif /* LWIP_UDP */\n#if LWIP_TCP\n  case NETCONN_TCP:\n    size = DEFAULT_TCP_RECVMBOX_SIZE;\n    break;\n#endif /* LWIP_TCP */\n  default:\n    LWIP_ASSERT(\"netconn_alloc: undefined netconn_type\", 0);\n    break;\n  }\n#endif\n\n  if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {\n    memp_free(MEMP_NETCONN, conn);\n    return NULL;\n  }\n  if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {\n    sys_sem_free(&conn->op_completed);\n    memp_free(MEMP_NETCONN, conn);\n    return NULL;\n  }\n\n#if LWIP_TCP\n  sys_mbox_set_invalid(&conn->acceptmbox);\n#endif\n  conn->state        = NETCONN_NONE;\n#if LWIP_SOCKET\n  /* initialize socket to -1 since 0 is a valid socket */\n  conn->socket       = -1;\n#endif /* LWIP_SOCKET */\n  conn->callback     = callback;\n#if LWIP_TCP\n  conn->current_msg  = NULL;\n  conn->write_offset = 0;\n#endif /* LWIP_TCP */\n#if LWIP_SO_RCVTIMEO\n  conn->recv_timeout = 0;\n#endif /* LWIP_SO_RCVTIMEO */\n#if LWIP_SO_RCVBUF\n  conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;\n  conn->recv_avail   = 0;\n#endif /* LWIP_SO_RCVBUF */\n  conn->flags = 0;\n  return conn;\n}\n\n/**\n * Delete a netconn and all its resources.\n * The pcb is NOT freed (since we might not be in the right thread context do this).\n *\n * @param conn the netconn to free\n */\nvoid\nnetconn_free(struct netconn *conn)\n{\n  LWIP_ASSERT(\"PCB must be deallocated outside this function\", conn->pcb.tcp == NULL);\n  LWIP_ASSERT(\"recvmbox must be deallocated before calling this function\",\n    !sys_mbox_valid(&conn->recvmbox));\n#if LWIP_TCP\n  LWIP_ASSERT(\"acceptmbox must be deallocated before calling this function\",\n    !sys_mbox_valid(&conn->acceptmbox));\n#endif /* LWIP_TCP */\n\n  sys_sem_free(&conn->op_completed);\n  sys_sem_set_invalid(&conn->op_completed);\n\n  memp_free(MEMP_NETCONN, conn);\n}\n\n/**\n * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in\n * these mboxes\n *\n * @param conn the netconn to free\n * @bytes_drained bytes drained from recvmbox\n * @accepts_drained pending connections drained from acceptmbox\n */\nstatic void\nnetconn_drain(struct netconn *conn)\n{\n  void *mem;\n#if LWIP_TCP\n  struct pbuf *p;\n#endif /* LWIP_TCP */\n\n  /* This runs in tcpip_thread, so we don't need to lock against rx packets */\n\n  /* Delete and drain the recvmbox. */\n  if (sys_mbox_valid(&conn->recvmbox)) {\n    while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {\n#if LWIP_TCP\n      if (conn->type == NETCONN_TCP) {\n        if(mem != NULL) {\n          p = (struct pbuf*)mem;\n          /* pcb might be set to NULL already by err_tcp() */\n          if (conn->pcb.tcp != NULL) {\n            tcp_recved(conn->pcb.tcp, p->tot_len);\n          }\n          pbuf_free(p);\n        }\n      } else\n#endif /* LWIP_TCP */\n      {\n        netbuf_delete((struct netbuf *)mem);\n      }\n    }\n    sys_mbox_free(&conn->recvmbox);\n    sys_mbox_set_invalid(&conn->recvmbox);\n  }\n\n  /* Delete and drain the acceptmbox. */\n#if LWIP_TCP\n  if (sys_mbox_valid(&conn->acceptmbox)) {\n    while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {\n      struct netconn *newconn = (struct netconn *)mem;\n      /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */\n      /* pcb might be set to NULL already by err_tcp() */\n      if (conn->pcb.tcp != NULL) {\n        tcp_accepted(conn->pcb.tcp);\n      }\n      /* drain recvmbox */\n      netconn_drain(newconn);\n      if (newconn->pcb.tcp != NULL) {\n        tcp_abort(newconn->pcb.tcp);\n        newconn->pcb.tcp = NULL;\n      }\n      netconn_free(newconn);\n    }\n    sys_mbox_free(&conn->acceptmbox);\n    sys_mbox_set_invalid(&conn->acceptmbox);\n  }\n#endif /* LWIP_TCP */\n}\n\n#if LWIP_TCP\n/**\n * Internal helper function to close a TCP netconn: since this sometimes\n * doesn't work at the first attempt, this function is called from multiple\n * places.\n *\n * @param conn the TCP netconn to close\n */\nstatic void\ndo_close_internal(struct netconn *conn)\n{\n  err_t err;\n  u8_t shut, shut_rx, shut_tx, close;\n\n  LWIP_ASSERT(\"invalid conn\", (conn != NULL));\n  LWIP_ASSERT(\"this is for tcp netconns only\", (conn->type == NETCONN_TCP));\n  LWIP_ASSERT(\"conn must be in state NETCONN_CLOSE\", (conn->state == NETCONN_CLOSE));\n  LWIP_ASSERT(\"pcb already closed\", (conn->pcb.tcp != NULL));\n  LWIP_ASSERT(\"conn->current_msg != NULL\", conn->current_msg != NULL);\n\n  shut = conn->current_msg->msg.sd.shut;\n  shut_rx = shut & NETCONN_SHUT_RD;\n  shut_tx = shut & NETCONN_SHUT_WR;\n  /* shutting down both ends is the same as closing */\n  close = shut == NETCONN_SHUT_RDWR;\n\n  /* Set back some callback pointers */\n  if (close) {\n    tcp_arg(conn->pcb.tcp, NULL);\n  }\n  if (conn->pcb.tcp->state == LISTEN) {\n    tcp_accept(conn->pcb.tcp, NULL);\n  } else {\n    /* some callbacks have to be reset if tcp_close is not successful */\n    if (shut_rx) {\n      tcp_recv(conn->pcb.tcp, NULL);\n      tcp_accept(conn->pcb.tcp, NULL);\n    }\n    if (shut_tx) {\n      tcp_sent(conn->pcb.tcp, NULL);\n    }\n    if (close) {\n      tcp_poll(conn->pcb.tcp, NULL, 4);\n      tcp_err(conn->pcb.tcp, NULL);\n    }\n  }\n  /* Try to close the connection */\n  if (shut == NETCONN_SHUT_RDWR) {\n    err = tcp_close(conn->pcb.tcp);\n  } else {\n    err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);\n  }\n  if (err == ERR_OK) {\n    /* Closing succeeded */\n    conn->current_msg->err = ERR_OK;\n    conn->current_msg = NULL;\n    conn->state = NETCONN_NONE;\n    /* Set back some callback pointers as conn is going away */\n    conn->pcb.tcp = NULL;\n    /* Trigger select() in socket layer. Make sure everybody notices activity\n       on the connection, error first! */\n    if (close) {\n      API_EVENT(conn, NETCONN_EVT_ERROR, 0);\n    }\n    if (shut_rx) {\n      API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\n    }\n    if (shut_tx) {\n      API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);\n    }\n    /* wake up the application task */\n    sys_sem_signal(&conn->op_completed);\n  } else {\n    /* Closing failed, restore some of the callbacks */\n    /* Closing of listen pcb will never fail! */\n    LWIP_ASSERT(\"Closing a listen pcb may not fail!\", (conn->pcb.tcp->state != LISTEN));\n    tcp_sent(conn->pcb.tcp, sent_tcp);\n    tcp_poll(conn->pcb.tcp, poll_tcp, 4);\n    tcp_err(conn->pcb.tcp, err_tcp);\n    tcp_arg(conn->pcb.tcp, conn);\n    /* don't restore recv callback: we don't want to receive any more data */\n  }\n  /* If closing didn't succeed, we get called again either\n     from poll_tcp or from sent_tcp */\n}\n#endif /* LWIP_TCP */\n\n/**\n * Delete the pcb inside a netconn.\n * Called from netconn_delete.\n *\n * @param msg the api_msg_msg pointing to the connection\n */\nvoid\ndo_delconn(struct api_msg_msg *msg)\n{\n  /* @todo TCP: abort running write/connect? */\n if ((msg->conn->state != NETCONN_NONE) &&\n     (msg->conn->state != NETCONN_LISTEN) &&\n     (msg->conn->state != NETCONN_CONNECT)) {\n    /* this only happens for TCP netconns */\n    LWIP_ASSERT(\"msg->conn->type == NETCONN_TCP\", msg->conn->type == NETCONN_TCP);\n    msg->err = ERR_INPROGRESS;\n  } else {\n    LWIP_ASSERT(\"blocking connect in progress\",\n      (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));\n    /* Drain and delete mboxes */\n    netconn_drain(msg->conn);\n\n    if (msg->conn->pcb.tcp != NULL) {\n\n      switch (NETCONNTYPE_GROUP(msg->conn->type)) {\n#if LWIP_RAW\n      case NETCONN_RAW:\n        raw_remove(msg->conn->pcb.raw);\n        break;\n#endif /* LWIP_RAW */\n#if LWIP_UDP\n      case NETCONN_UDP:\n        msg->conn->pcb.udp->recv_arg = NULL;\n        udp_remove(msg->conn->pcb.udp);\n        break;\n#endif /* LWIP_UDP */\n#if LWIP_TCP\n      case NETCONN_TCP:\n        LWIP_ASSERT(\"already writing or closing\", msg->conn->current_msg == NULL &&\n          msg->conn->write_offset == 0);\n        msg->conn->state = NETCONN_CLOSE;\n        msg->msg.sd.shut = NETCONN_SHUT_RDWR;\n        msg->conn->current_msg = msg;\n        do_close_internal(msg->conn);\n        /* API_EVENT is called inside do_close_internal, before releasing\n           the application thread, so we can return at this point! */\n        return;\n#endif /* LWIP_TCP */\n      default:\n        break;\n      }\n      msg->conn->pcb.tcp = NULL;\n    }\n    /* tcp netconns don't come here! */\n\n    /* @todo: this lets select make the socket readable and writable,\n       which is wrong! errfd instead? */\n    API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);\n    API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);\n  }\n  if (sys_sem_valid(&msg->conn->op_completed)) {\n    sys_sem_signal(&msg->conn->op_completed);\n  }\n}\n\n/**\n * Bind a pcb contained in a netconn\n * Called from netconn_bind.\n *\n * @param msg the api_msg_msg pointing to the connection and containing\n *            the IP address and port to bind to\n */\nvoid\ndo_bind(struct api_msg_msg *msg)\n{\n  if (ERR_IS_FATAL(msg->conn->last_err)) {\n    msg->err = msg->conn->last_err;\n  } else {\n    msg->err = ERR_VAL;\n    if (msg->conn->pcb.tcp != NULL) {\n      switch (NETCONNTYPE_GROUP(msg->conn->type)) {\n#if LWIP_RAW\n      case NETCONN_RAW:\n        msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);\n        break;\n#endif /* LWIP_RAW */\n#if LWIP_UDP\n      case NETCONN_UDP:\n        msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);\n        break;\n#endif /* LWIP_UDP */\n#if LWIP_TCP\n      case NETCONN_TCP:\n        msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);\n        break;\n#endif /* LWIP_TCP */\n      default:\n        break;\n      }\n    }\n  }\n  TCPIP_APIMSG_ACK(msg);\n}\n\n#if LWIP_TCP\n/**\n * TCP callback function if a connection (opened by tcp_connect/do_connect) has\n * been established (or reset by the remote host).\n *\n * @see tcp.h (struct tcp_pcb.connected) for parameters and return values\n */\nstatic err_t\ndo_connected(void *arg, struct tcp_pcb *pcb, err_t err)\n{\n  struct netconn *conn;\n  int was_blocking;\n\n  LWIP_UNUSED_ARG(pcb);\n\n  conn = (struct netconn *)arg;\n\n  if (conn == NULL) {\n    return ERR_VAL;\n  }\n\n  LWIP_ASSERT(\"conn->state == NETCONN_CONNECT\", conn->state == NETCONN_CONNECT);\n  LWIP_ASSERT(\"(conn->current_msg != NULL) || conn->in_non_blocking_connect\",\n    (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));\n\n  if (conn->current_msg != NULL) {\n    conn->current_msg->err = err;\n  }\n  if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {\n    setup_tcp(conn);\n  }\n  was_blocking = !IN_NONBLOCKING_CONNECT(conn);\n  SET_NONBLOCKING_CONNECT(conn, 0);\n  conn->current_msg = NULL;\n  conn->state = NETCONN_NONE;\n  if (!was_blocking) {\n    SYS_ARCH_DECL_PROTECT(lev);\n    SYS_ARCH_PROTECT(lev);\n    if (conn->last_err == ERR_INPROGRESS) {\n      conn->last_err = ERR_OK;\n    }\n    SYS_ARCH_UNPROTECT(lev);\n  }\n  API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);\n\n  if (was_blocking) {\n    sys_sem_signal(&conn->op_completed);\n  }\n  return ERR_OK;\n}\n#endif /* LWIP_TCP */\n\n/**\n * Connect a pcb contained inside a netconn\n * Called from netconn_connect.\n *\n * @param msg the api_msg_msg pointing to the connection and containing\n *            the IP address and port to connect to\n */\nvoid\ndo_connect(struct api_msg_msg *msg)\n{\n  if (msg->conn->pcb.tcp == NULL) {\n    /* This may happen when calling netconn_connect() a second time */\n    msg->err = ERR_CLSD;\n  } else {\n    switch (NETCONNTYPE_GROUP(msg->conn->type)) {\n#if LWIP_RAW\n  case NETCONN_RAW:\n    msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);\n    break;\n#endif /* LWIP_RAW */\n#if LWIP_UDP\n  case NETCONN_UDP:\n    msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);\n    break;\n#endif /* LWIP_UDP */\n#if LWIP_TCP\n  case NETCONN_TCP:\n    /* Prevent connect while doing any other action. */\n    if (msg->conn->state != NETCONN_NONE) {\n      msg->err = ERR_ISCONN;\n    } else {\n      setup_tcp(msg->conn);\n      msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,\n        msg->msg.bc.port, do_connected);\n      if (msg->err == ERR_OK) {\n        u8_t non_blocking = netconn_is_nonblocking(msg->conn);\n        msg->conn->state = NETCONN_CONNECT;\n        SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);\n        if (non_blocking) {\n          msg->err = ERR_INPROGRESS;\n        } else {\n          msg->conn->current_msg = msg;\n          /* sys_sem_signal() is called from do_connected (or err_tcp()),\n          * when the connection is established! */\n          return;\n        }\n      }\n    }\n    break;\n#endif /* LWIP_TCP */\n  default:\n    LWIP_ERROR(\"Invalid netconn type\", 0, do{ msg->err = ERR_VAL; }while(0));\n    break;\n    }\n  }\n  sys_sem_signal(&msg->conn->op_completed);\n}\n\n/**\n * Connect a pcb contained inside a netconn\n * Only used for UDP netconns.\n * Called from netconn_disconnect.\n *\n * @param msg the api_msg_msg pointing to the connection to disconnect\n */\nvoid\ndo_disconnect(struct api_msg_msg *msg)\n{\n#if LWIP_UDP\n  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {\n    udp_disconnect(msg->conn->pcb.udp);\n    msg->err = ERR_OK;\n  } else\n#endif /* LWIP_UDP */\n  {\n    msg->err = ERR_VAL;\n  }\n  TCPIP_APIMSG_ACK(msg);\n}\n\n#if LWIP_TCP\n/**\n * Set a TCP pcb contained in a netconn into listen mode\n * Called from netconn_listen.\n *\n * @param msg the api_msg_msg pointing to the connection\n */\nvoid\ndo_listen(struct api_msg_msg *msg)\n{\n  if (ERR_IS_FATAL(msg->conn->last_err)) {\n    msg->err = msg->conn->last_err;\n  } else {\n    msg->err = ERR_CONN;\n    if (msg->conn->pcb.tcp != NULL) {\n      if (msg->conn->type == NETCONN_TCP) {\n        if (msg->conn->state == NETCONN_NONE) {\n#if TCP_LISTEN_BACKLOG\n          struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);\n#else  /* TCP_LISTEN_BACKLOG */\n          struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);\n#endif /* TCP_LISTEN_BACKLOG */\n          if (lpcb == NULL) {\n            /* in this case, the old pcb is still allocated */\n            msg->err = ERR_MEM;\n          } else {\n            /* delete the recvmbox and allocate the acceptmbox */\n            if (sys_mbox_valid(&msg->conn->recvmbox)) {\n              /** @todo: should we drain the recvmbox here? */\n              sys_mbox_free(&msg->conn->recvmbox);\n              sys_mbox_set_invalid(&msg->conn->recvmbox);\n            }\n            msg->err = ERR_OK;\n            if (!sys_mbox_valid(&msg->conn->acceptmbox)) {\n              msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);\n            }\n            if (msg->err == ERR_OK) {\n              msg->conn->state = NETCONN_LISTEN;\n              msg->conn->pcb.tcp = lpcb;\n              tcp_arg(msg->conn->pcb.tcp, msg->conn);\n              tcp_accept(msg->conn->pcb.tcp, accept_function);\n            } else {\n              /* since the old pcb is already deallocated, free lpcb now */\n              tcp_close(lpcb);\n              msg->conn->pcb.tcp = NULL;\n            }\n          }\n        }\n      }\n    }\n  }\n  TCPIP_APIMSG_ACK(msg);\n}\n#endif /* LWIP_TCP */\n\n/**\n * Send some data on a RAW or UDP pcb contained in a netconn\n * Called from netconn_send\n *\n * @param msg the api_msg_msg pointing to the connection\n */\nvoid\ndo_send(struct api_msg_msg *msg)\n{\n  if (ERR_IS_FATAL(msg->conn->last_err)) {\n    msg->err = msg->conn->last_err;\n  } else {\n    msg->err = ERR_CONN;\n    if (msg->conn->pcb.tcp != NULL) {\n      switch (NETCONNTYPE_GROUP(msg->conn->type)) {\n#if LWIP_RAW\n      case NETCONN_RAW:\n        if (ip_addr_isany(&msg->msg.b->addr)) {\n          msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);\n        } else {\n          msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);\n        }\n        break;\n#endif\n#if LWIP_UDP\n      case NETCONN_UDP:\n#if LWIP_CHECKSUM_ON_COPY\n        if (ip_addr_isany(&msg->msg.b->addr)) {\n          msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,\n            msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);\n        } else {\n          msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,\n            &msg->msg.b->addr, msg->msg.b->port,\n            msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);\n        }\n#else /* LWIP_CHECKSUM_ON_COPY */\n        if (ip_addr_isany(&msg->msg.b->addr)) {\n          msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);\n        } else {\n          msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);\n        }\n#endif /* LWIP_CHECKSUM_ON_COPY */\n        break;\n#endif /* LWIP_UDP */\n      default:\n        break;\n      }\n    }\n  }\n  TCPIP_APIMSG_ACK(msg);\n}\n\n#if LWIP_TCP\n/**\n * Indicate data has been received from a TCP pcb contained in a netconn\n * Called from netconn_recv\n *\n * @param msg the api_msg_msg pointing to the connection\n */\nvoid\ndo_recv(struct api_msg_msg *msg)\n{\n  msg->err = ERR_OK;\n  if (msg->conn->pcb.tcp != NULL) {\n    if (msg->conn->type == NETCONN_TCP) {\n#if TCP_LISTEN_BACKLOG\n      if (msg->conn->pcb.tcp->state == LISTEN) {\n        tcp_accepted(msg->conn->pcb.tcp);\n      } else\n#endif /* TCP_LISTEN_BACKLOG */\n      {\n        u32_t remaining = msg->msg.r.len;\n        do {\n          u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;\n          tcp_recved(msg->conn->pcb.tcp, recved);\n          remaining -= recved;\n        }while(remaining != 0);\n      }\n    }\n  }\n  TCPIP_APIMSG_ACK(msg);\n}\n\n/**\n * See if more data needs to be written from a previous call to netconn_write.\n * Called initially from do_write. If the first call can't send all data\n * (because of low memory or empty send-buffer), this function is called again\n * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the\n * blocking application thread (waiting in netconn_write) is released.\n *\n * @param conn netconn (that is currently in state NETCONN_WRITE) to process\n * @return ERR_OK\n *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished\n */\nstatic err_t\ndo_writemore(struct netconn *conn)\n{\n  err_t err = ERR_OK;\n  void *dataptr;\n  u16_t len, available;\n  u8_t write_finished = 0;\n  size_t diff;\n  u8_t dontblock = netconn_is_nonblocking(conn) ||\n       (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);\n  u8_t apiflags = conn->current_msg->msg.w.apiflags;\n\n  LWIP_ASSERT(\"conn != NULL\", conn != NULL);\n  LWIP_ASSERT(\"conn->state == NETCONN_WRITE\", (conn->state == NETCONN_WRITE));\n  LWIP_ASSERT(\"conn->current_msg != NULL\", conn->current_msg != NULL);\n  LWIP_ASSERT(\"conn->pcb.tcp != NULL\", conn->pcb.tcp != NULL);\n  LWIP_ASSERT(\"conn->write_offset < conn->current_msg->msg.w.len\",\n    conn->write_offset < conn->current_msg->msg.w.len);\n\n  dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;\n  diff = conn->current_msg->msg.w.len - conn->write_offset;\n  if (diff > 0xffffUL) { /* max_u16_t */\n    len = 0xffff;\n#if LWIP_TCPIP_CORE_LOCKING\n    conn->flags |= NETCONN_FLAG_WRITE_DELAYED;\n#endif\n    apiflags |= TCP_WRITE_FLAG_MORE;\n  } else {\n    len = (u16_t)diff;\n  }\n  available = tcp_sndbuf(conn->pcb.tcp);\n  if (available < len) {\n    /* don't try to write more than sendbuf */\n    len = available;\n#if LWIP_TCPIP_CORE_LOCKING\n    conn->flags |= NETCONN_FLAG_WRITE_DELAYED;\n#endif\n    apiflags |= TCP_WRITE_FLAG_MORE;\n  }\n  if (dontblock && (len < conn->current_msg->msg.w.len)) {\n    /* failed to send all data at once -> nonblocking write not possible */\n    err = ERR_MEM;\n  }\n  if (err == ERR_OK) {\n    LWIP_ASSERT(\"do_writemore: invalid length!\", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));\n    err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);\n  }\n  if (dontblock && (err == ERR_MEM)) {\n    /* nonblocking write failed */\n    write_finished = 1;\n    err = ERR_WOULDBLOCK;\n    /* let poll_tcp check writable space to mark the pcb\n       writable again */\n    conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;\n    /* let select mark this pcb as non-writable. */\n    API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);\n  } else {\n    /* if OK or memory error, check available space */\n    if (((err == ERR_OK) || (err == ERR_MEM)) &&\n        ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||\n         (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) {\n      /* The queued byte- or pbuf-count exceeds the configured low-water limit,\n         let select mark this pcb as non-writable. */\n      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);\n    }\n\n    if (err == ERR_OK) {\n      conn->write_offset += len;\n      if (conn->write_offset == conn->current_msg->msg.w.len) {\n        /* everything was written */\n        write_finished = 1;\n        conn->write_offset = 0;\n      }\n      tcp_output(conn->pcb.tcp);\n    } else if (err == ERR_MEM) {\n      /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called\n         we do NOT return to the application thread, since ERR_MEM is\n         only a temporary error! */\n\n      /* tcp_write returned ERR_MEM, try tcp_output anyway */\n      tcp_output(conn->pcb.tcp);\n\n  #if LWIP_TCPIP_CORE_LOCKING\n      conn->flags |= NETCONN_FLAG_WRITE_DELAYED;\n  #endif\n    } else {\n      /* On errors != ERR_MEM, we don't try writing any more but return\n         the error to the application thread. */\n      write_finished = 1;\n    }\n  }\n\n  if (write_finished) {\n    /* everything was written: set back connection state\n       and back to application task */\n    conn->current_msg->err = err;\n    conn->current_msg = NULL;\n    conn->state = NETCONN_NONE;\n#if LWIP_TCPIP_CORE_LOCKING\n    if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0)\n#endif\n    {\n      sys_sem_signal(&conn->op_completed);\n    }\n  }\n#if LWIP_TCPIP_CORE_LOCKING\n  else\n    return ERR_MEM;\n#endif\n  return ERR_OK;\n}\n#endif /* LWIP_TCP */\n\n/**\n * Send some data on a TCP pcb contained in a netconn\n * Called from netconn_write\n *\n * @param msg the api_msg_msg pointing to the connection\n */\nvoid\ndo_write(struct api_msg_msg *msg)\n{\n  if (ERR_IS_FATAL(msg->conn->last_err)) {\n    msg->err = msg->conn->last_err;\n  } else {\n    if (msg->conn->type == NETCONN_TCP) {\n#if LWIP_TCP\n      if (msg->conn->state != NETCONN_NONE) {\n        /* netconn is connecting, closing or in blocking write */\n        msg->err = ERR_INPROGRESS;\n      } else if (msg->conn->pcb.tcp != NULL) {\n        msg->conn->state = NETCONN_WRITE;\n        /* set all the variables used by do_writemore */\n        LWIP_ASSERT(\"already writing or closing\", msg->conn->current_msg == NULL &&\n          msg->conn->write_offset == 0);\n        LWIP_ASSERT(\"msg->msg.w.len != 0\", msg->msg.w.len != 0);\n        msg->conn->current_msg = msg;\n        msg->conn->write_offset = 0;\n#if LWIP_TCPIP_CORE_LOCKING\n        msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;\n        if (do_writemore(msg->conn) != ERR_OK) {\n          LWIP_ASSERT(\"state!\", msg->conn->state == NETCONN_WRITE);\n          UNLOCK_TCPIP_CORE();\n          sys_arch_sem_wait(&msg->conn->op_completed, 0);\n          LOCK_TCPIP_CORE();\n          LWIP_ASSERT(\"state!\", msg->conn->state == NETCONN_NONE);\n        }\n#else /* LWIP_TCPIP_CORE_LOCKING */\n        do_writemore(msg->conn);\n#endif /* LWIP_TCPIP_CORE_LOCKING */\n        /* for both cases: if do_writemore was called, don't ACK the APIMSG\n           since do_writemore ACKs it! */\n        return;\n      } else {\n        msg->err = ERR_CONN;\n      }\n#else /* LWIP_TCP */\n      msg->err = ERR_VAL;\n#endif /* LWIP_TCP */\n#if (LWIP_UDP || LWIP_RAW)\n    } else {\n      msg->err = ERR_VAL;\n#endif /* (LWIP_UDP || LWIP_RAW) */\n    }\n  }\n  TCPIP_APIMSG_ACK(msg);\n}\n\n/**\n * Return a connection's local or remote address\n * Called from netconn_getaddr\n *\n * @param msg the api_msg_msg pointing to the connection\n */\nvoid\ndo_getaddr(struct api_msg_msg *msg)\n{\n  if (msg->conn->pcb.ip != NULL) {\n    *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip :\n                             msg->conn->pcb.ip->remote_ip);\n\n    msg->err = ERR_OK;\n    switch (NETCONNTYPE_GROUP(msg->conn->type)) {\n#if LWIP_RAW\n    case NETCONN_RAW:\n      if (msg->msg.ad.local) {\n        *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;\n      } else {\n        /* return an error as connecting is only a helper for upper layers */\n        msg->err = ERR_CONN;\n      }\n      break;\n#endif /* LWIP_RAW */\n#if LWIP_UDP\n    case NETCONN_UDP:\n      if (msg->msg.ad.local) {\n        *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;\n      } else {\n        if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {\n          msg->err = ERR_CONN;\n        } else {\n          *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;\n        }\n      }\n      break;\n#endif /* LWIP_UDP */\n#if LWIP_TCP\n    case NETCONN_TCP:\n      *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);\n      break;\n#endif /* LWIP_TCP */\n    default:\n      LWIP_ASSERT(\"invalid netconn_type\", 0);\n      break;\n    }\n  } else {\n    msg->err = ERR_CONN;\n  }\n  TCPIP_APIMSG_ACK(msg);\n}\n\n/**\n * Close a TCP pcb contained in a netconn\n * Called from netconn_close\n *\n * @param msg the api_msg_msg pointing to the connection\n */\nvoid\ndo_close(struct api_msg_msg *msg)\n{\n#if LWIP_TCP\n  /* @todo: abort running write/connect? */\n  if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {\n    /* this only happens for TCP netconns */\n    LWIP_ASSERT(\"msg->conn->type == NETCONN_TCP\", msg->conn->type == NETCONN_TCP);\n    msg->err = ERR_INPROGRESS;\n  } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {\n    if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {\n      /* LISTEN doesn't support half shutdown */\n      msg->err = ERR_CONN;\n    } else {\n      if (msg->msg.sd.shut & NETCONN_SHUT_RD) {\n        /* Drain and delete mboxes */\n        netconn_drain(msg->conn);\n      }\n      LWIP_ASSERT(\"already writing or closing\", msg->conn->current_msg == NULL &&\n        msg->conn->write_offset == 0);\n      msg->conn->state = NETCONN_CLOSE;\n      msg->conn->current_msg = msg;\n      do_close_internal(msg->conn);\n      /* for tcp netconns, do_close_internal ACKs the message */\n      return;\n    }\n  } else\n#endif /* LWIP_TCP */\n  {\n    msg->err = ERR_VAL;\n  }\n  sys_sem_signal(&msg->conn->op_completed);\n}\n\n#if LWIP_IGMP\n/**\n * Join multicast groups for UDP netconns.\n * Called from netconn_join_leave_group\n *\n * @param msg the api_msg_msg pointing to the connection\n */\nvoid\ndo_join_leave_group(struct api_msg_msg *msg)\n{ \n  if (ERR_IS_FATAL(msg->conn->last_err)) {\n    msg->err = msg->conn->last_err;\n  } else {\n    if (msg->conn->pcb.tcp != NULL) {\n      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {\n#if LWIP_UDP\n        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {\n          msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);\n        } else {\n          msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);\n        }\n#endif /* LWIP_UDP */\n#if (LWIP_TCP || LWIP_RAW)\n      } else {\n        msg->err = ERR_VAL;\n#endif /* (LWIP_TCP || LWIP_RAW) */\n      }\n    } else {\n      msg->err = ERR_CONN;\n    }\n  }\n  TCPIP_APIMSG_ACK(msg);\n}\n#endif /* LWIP_IGMP */\n\n#if LWIP_DNS\n/**\n * Callback function that is called when DNS name is resolved\n * (or on timeout). A waiting application thread is waked up by\n * signaling the semaphore.\n */\nstatic void\ndo_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)\n{\n  struct dns_api_msg *msg = (struct dns_api_msg*)arg;\n\n  LWIP_ASSERT(\"DNS response for wrong host name\", strcmp(msg->name, name) == 0);\n  LWIP_UNUSED_ARG(name);\n\n  if (ipaddr == NULL) {\n    /* timeout or memory error */\n    *msg->err = ERR_VAL;\n  } else {\n    /* address was resolved */\n    *msg->err = ERR_OK;\n    *msg->addr = *ipaddr;\n  }\n  /* wake up the application task waiting in netconn_gethostbyname */\n  sys_sem_signal(msg->sem);\n}\n\n/**\n * Execute a DNS query\n * Called from netconn_gethostbyname\n *\n * @param arg the dns_api_msg pointing to the query\n */\nvoid\ndo_gethostbyname(void *arg)\n{\n  struct dns_api_msg *msg = (struct dns_api_msg*)arg;\n\n  *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);\n  if (*msg->err != ERR_INPROGRESS) {\n    /* on error or immediate success, wake up the application\n     * task waiting in netconn_gethostbyname */\n    sys_sem_signal(msg->sem);\n  }\n}\n#endif /* LWIP_DNS */\n\n#endif /* LWIP_NETCONN */\n"
  },
  {
    "path": "app/lwip/api/err.c",
    "content": "/**\n * @file\n * Error Management module\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/err.h\"\n\n#ifdef LWIP_DEBUG\n\nstatic const char *err_strerr[] = {\n           \"Ok.\",                    /* ERR_OK          0  */\n           \"Out of memory error.\",   /* ERR_MEM        -1  */\n           \"Buffer error.\",          /* ERR_BUF        -2  */\n           \"Timeout.\",               /* ERR_TIMEOUT    -3  */\n           \"Routing problem.\",       /* ERR_RTE        -4  */\n           \"Operation in progress.\", /* ERR_INPROGRESS -5  */\n           \"Illegal value.\",         /* ERR_VAL        -6  */\n           \"Operation would block.\", /* ERR_WOULDBLOCK -7  */\n           \"Connection aborted.\",    /* ERR_ABRT       -8  */\n           \"Connection reset.\",      /* ERR_RST        -9  */\n           \"Connection closed.\",     /* ERR_CLSD       -10 */\n           \"Not connected.\",         /* ERR_CONN       -11 */\n           \"Illegal argument.\",      /* ERR_ARG        -12 */\n           \"Address in use.\",        /* ERR_USE        -13 */\n           \"Low-level netif error.\", /* ERR_IF         -14 */\n           \"Already connected.\",     /* ERR_ISCONN     -15 */\n};\n\n/**\n * Convert an lwip internal error to a string representation.\n *\n * @param err an lwip internal err_t\n * @return a string representation for err\n */\nconst char *\nlwip_strerr(err_t err)\n{\n  return err_strerr[-err];\n\n}\n\n#endif /* LWIP_DEBUG */\n"
  },
  {
    "path": "app/lwip/api/netbuf.c",
    "content": "/**\n * @file\n * Network buffer management\n *\n */\n \n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/netbuf.h\"\n#include \"lwip/memp.h\"\n\n#include <string.h>\n\n/**\n * Create (allocate) and initialize a new netbuf.\n * The netbuf doesn't yet contain a packet buffer!\n * һµnetbufռ䣬κݿռ\n * @return a pointer to a new netbuf\n *         NULL on lack of memory\n */\nstruct\nnetbuf *netbuf_new(void)\n{\n  struct netbuf *buf;\n\n  buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);\n  if (buf != NULL) {\n    buf->p = NULL;\n    buf->ptr = NULL;\n    ip_addr_set_any(&buf->addr);\n    buf->port = 0;\n#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY\n#if LWIP_CHECKSUM_ON_COPY\n    buf->flags = 0;\n#endif /* LWIP_CHECKSUM_ON_COPY */\n    buf->toport_chksum = 0;\n#if LWIP_NETBUF_RECVINFO\n    ip_addr_set_any(&buf->toaddr);\n#endif /* LWIP_NETBUF_RECVINFO */\n#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */\n    return buf;\n  } else {\n    return NULL;\n  }\n}\n\n/**\n * Deallocate a netbuf allocated by netbuf_new().\n * ͷһnetbufռ\n * @param buf pointer to a netbuf allocated by netbuf_new()\n */\nvoid\nnetbuf_delete(struct netbuf *buf)\n{\n  if (buf != NULL) {\n    if (buf->p != NULL) {\n      pbuf_free(buf->p);\n      buf->p = buf->ptr = NULL;\n    }\n    memp_free(MEMP_NETBUF, buf);\n  }\n}\n\n/**\n * Allocate memory for a packet buffer for a given netbuf.\n *ΪnetbufṹsizeСݿռ\n * @param buf the netbuf for which to allocate a packet buffer\n * @param size the size of the packet buffer to allocate\n * @return pointer to the allocated memory\n *         NULL if no memory could be allocated\n */\nvoid *\nnetbuf_alloc(struct netbuf *buf, u16_t size)\n{\n  LWIP_ERROR(\"netbuf_alloc: invalid buf\", (buf != NULL), return NULL;);\n\n  /* Deallocate any previously allocated memory. */\n  if (buf->p != NULL) {\n    pbuf_free(buf->p);\n  }\n  buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);\n  if (buf->p == NULL) {\n     return NULL;\n  }\n  LWIP_ASSERT(\"check that first pbuf can hold size\",\n             (buf->p->len >= size));\n  buf->ptr = buf->p;\n  return buf->p->payload;\n}\n\n/**\n * Free the packet buffer included in a netbuf\n *ͷnetbufṹָpbuf\n * @param buf pointer to the netbuf which contains the packet buffer to free\n */\nvoid\nnetbuf_free(struct netbuf *buf)\n{\n  LWIP_ERROR(\"netbuf_free: invalid buf\", (buf != NULL), return;);\n  if (buf->p != NULL) {\n    pbuf_free(buf->p);\n  }\n  buf->p = buf->ptr = NULL;\n}\n\n/**\n * Let a netbuf reference existing (non-volatile) data.\n *\n * @param buf netbuf which should reference the data\n * @param dataptr pointer to the data to reference\n * @param size size of the data\n * @return ERR_OK if data is referenced\n *         ERR_MEM if data couldn't be referenced due to lack of memory\n */\nerr_t\nnetbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)\n{\n  LWIP_ERROR(\"netbuf_ref: invalid buf\", (buf != NULL), return ERR_ARG;);\n  if (buf->p != NULL) {\n    pbuf_free(buf->p);\n  }\n  buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);\n  if (buf->p == NULL) {\n    buf->ptr = NULL;\n    return ERR_MEM;\n  }\n  buf->p->payload = (void*)dataptr;\n  buf->p->len = buf->p->tot_len = size;\n  buf->ptr = buf->p;\n  return ERR_OK;\n}\n\n/**\n * Chain one netbuf to another (@see pbuf_chain)\n *\n * @param head the first netbuf\n * @param tail netbuf to chain after head, freed by this function, may not be reference after returning\n */\nvoid\nnetbuf_chain(struct netbuf *head, struct netbuf *tail)\n{\n  LWIP_ERROR(\"netbuf_ref: invalid head\", (head != NULL), return;);\n  LWIP_ERROR(\"netbuf_chain: invalid tail\", (tail != NULL), return;);\n  pbuf_cat(head->p, tail->p);\n  head->ptr = head->p;\n  memp_free(MEMP_NETBUF, tail);\n}\n\n/**\n * Get the data pointer and length of the data inside a netbuf.\n *\n * @param buf netbuf to get the data from\n * @param dataptr pointer to a void pointer where to store the data pointer\n * @param len pointer to an u16_t where the length of the data is stored\n * @return ERR_OK if the information was retreived,\n *         ERR_BUF on error.\n */\nerr_t\nnetbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)\n{\n  LWIP_ERROR(\"netbuf_data: invalid buf\", (buf != NULL), return ERR_ARG;);\n  LWIP_ERROR(\"netbuf_data: invalid dataptr\", (dataptr != NULL), return ERR_ARG;);\n  LWIP_ERROR(\"netbuf_data: invalid len\", (len != NULL), return ERR_ARG;);\n\n  if (buf->ptr == NULL) {\n    return ERR_BUF;\n  }\n  *dataptr = buf->ptr->payload;\n  *len = buf->ptr->len;\n  return ERR_OK;\n}\n\n/**\n * Move the current data pointer of a packet buffer contained in a netbuf\n * to the next part.\n * The packet buffer itself is not modified.\n *\n * @param buf the netbuf to modify\n * @return -1 if there is no next part\n *         1  if moved to the next part but now there is no next part\n *         0  if moved to the next part and there are still more parts\n */\ns8_t\nnetbuf_next(struct netbuf *buf)\n{\n  LWIP_ERROR(\"netbuf_free: invalid buf\", (buf != NULL), return -1;);\n  if (buf->ptr->next == NULL) {\n    return -1;\n  }\n  buf->ptr = buf->ptr->next;\n  if (buf->ptr->next == NULL) {\n    return 1;\n  }\n  return 0;\n}\n\n/**\n * Move the current data pointer of a packet buffer contained in a netbuf\n * to the beginning of the packet.\n * The packet buffer itself is not modified.\n *\n * @param buf the netbuf to modify\n */\nvoid\nnetbuf_first(struct netbuf *buf)\n{\n  LWIP_ERROR(\"netbuf_free: invalid buf\", (buf != NULL), return;);\n  buf->ptr = buf->p;\n}\n\n#endif /* LWIP_NETCONN */\n"
  },
  {
    "path": "app/lwip/api/netdb.c",
    "content": "/**\n * @file\n * API functions for name resolving\n *\n */\n\n/*\n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Simon Goldschmidt\n *\n */\n\n#include \"lwip/netdb.h\"\n\n#if LWIP_DNS && LWIP_SOCKET\n\n#include \"lwip/err.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/api.h\"\n#include \"lwip/dns.h\"\n\n#include <string.h>\n#include <stdlib.h>\n\n/** helper struct for gethostbyname_r to access the char* buffer */\nstruct gethostbyname_r_helper {\n  ip_addr_t *addrs;\n  ip_addr_t addr;\n  char *aliases;\n};\n\n/** h_errno is exported in netdb.h for access by applications. */\n#if LWIP_DNS_API_DECLARE_H_ERRNO\nint h_errno;\n#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */\n\n/** define \"hostent\" variables storage: 0 if we use a static (but unprotected)\n * set of variables for lwip_gethostbyname, 1 if we use a local storage */\n#ifndef LWIP_DNS_API_HOSTENT_STORAGE\n#define LWIP_DNS_API_HOSTENT_STORAGE 0\n#endif\n\n/** define \"hostent\" variables storage */\n#if LWIP_DNS_API_HOSTENT_STORAGE\n#define HOSTENT_STORAGE\n#else\n#define HOSTENT_STORAGE static\n#endif /* LWIP_DNS_API_STATIC_HOSTENT */\n\n/**\n * Returns an entry containing addresses of address family AF_INET\n * for the host with name name.\n * Due to dns_gethostbyname limitations, only one address is returned.\n *\n * @param name the hostname to resolve\n * @return an entry containing addresses of address family AF_INET\n *         for the host with name name\n */\nstruct hostent*\nlwip_gethostbyname(const char *name)\n{\n  err_t err;\n  ip_addr_t addr;\n\n  /* buffer variables for lwip_gethostbyname() */\n  HOSTENT_STORAGE struct hostent s_hostent;\n  HOSTENT_STORAGE char *s_aliases;\n  HOSTENT_STORAGE ip_addr_t s_hostent_addr;\n  HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];\n\n  /* query host IP address */\n  err = netconn_gethostbyname(name, &addr);\n  if (err != ERR_OK) {\n    LWIP_DEBUGF(DNS_DEBUG, (\"lwip_gethostbyname(%s) failed, err=%d\\n\", name, err));\n    h_errno = HOST_NOT_FOUND;\n    return NULL;\n  }\n\n  /* fill hostent */\n  s_hostent_addr = addr;\n  s_phostent_addr[0] = &s_hostent_addr;\n  s_phostent_addr[1] = NULL;\n  s_hostent.h_name = (char*)name;\n  s_hostent.h_aliases = &s_aliases;\n  s_hostent.h_addrtype = AF_INET;\n  s_hostent.h_length = sizeof(ip_addr_t);\n  s_hostent.h_addr_list = (char**)&s_phostent_addr;\n\n#if DNS_DEBUG\n  /* dump hostent */\n  LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_name           == %s\\n\", s_hostent.h_name));\n  LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_aliases        == %p\\n\", s_hostent.h_aliases));\n  if (s_hostent.h_aliases != NULL) {\n    u8_t idx;\n    for ( idx=0; s_hostent.h_aliases[idx]; idx++) {\n      LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_aliases[%i]->   == %p\\n\", idx, s_hostent.h_aliases[idx]));\n      LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_aliases[%i]->   == %s\\n\", idx, s_hostent.h_aliases[idx]));\n    }\n  }\n  LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_addrtype       == %d\\n\", s_hostent.h_addrtype));\n  LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_length         == %d\\n\", s_hostent.h_length));\n  LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_addr_list      == %p\\n\", s_hostent.h_addr_list));\n  if (s_hostent.h_addr_list != NULL) {\n    u8_t idx;\n    for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {\n      LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_addr_list[%i]   == %p\\n\", idx, s_hostent.h_addr_list[idx]));\n      LWIP_DEBUGF(DNS_DEBUG, (\"hostent.h_addr_list[%i]-> == %s\\n\", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx])));\n    }\n  }\n#endif /* DNS_DEBUG */\n\n#if LWIP_DNS_API_HOSTENT_STORAGE\n  /* this function should return the \"per-thread\" hostent after copy from s_hostent */\n  return sys_thread_hostent(&s_hostent);\n#else\n  return &s_hostent;\n#endif /* LWIP_DNS_API_HOSTENT_STORAGE */\n}\n\n/**\n * Thread-safe variant of lwip_gethostbyname: instead of using a static\n * buffer, this function takes buffer and errno pointers as arguments\n * and uses these for the result.\n *\n * @param name the hostname to resolve\n * @param ret pre-allocated struct where to store the result\n * @param buf pre-allocated buffer where to store additional data\n * @param buflen the size of buf\n * @param result pointer to a hostent pointer that is set to ret on success\n *               and set to zero on error\n * @param h_errnop pointer to an int where to store errors (instead of modifying\n *                 the global h_errno)\n * @return 0 on success, non-zero on error, additional error information\n *         is stored in *h_errnop instead of h_errno to be thread-safe\n */\nint\nlwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,\n                size_t buflen, struct hostent **result, int *h_errnop)\n{\n  err_t err;\n  struct gethostbyname_r_helper *h;\n  char *hostname;\n  size_t namelen;\n  int lh_errno;\n\n  if (h_errnop == NULL) {\n    /* ensure h_errnop is never NULL */\n    h_errnop = &lh_errno;\n  }\n\n  if (result == NULL) {\n    /* not all arguments given */\n    *h_errnop = EINVAL;\n    return -1;\n  }\n  /* first thing to do: set *result to nothing */\n  *result = NULL;\n  if ((name == NULL) || (ret == NULL) || (buf == 0)) {\n    /* not all arguments given */\n    *h_errnop = EINVAL;\n    return -1;\n  }\n\n  namelen = strlen(name);\n  if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {\n    /* buf can't hold the data needed + a copy of name */\n    *h_errnop = ERANGE;\n    return -1;\n  }\n\n  h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);\n  hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);\n\n  /* query host IP address */\n  err = netconn_gethostbyname(name, &(h->addr));\n  if (err != ERR_OK) {\n    LWIP_DEBUGF(DNS_DEBUG, (\"lwip_gethostbyname(%s) failed, err=%d\\n\", name, err));\n    *h_errnop = ENSRNOTFOUND;\n    return -1;\n  }\n\n  /* copy the hostname into buf */\n  MEMCPY(hostname, name, namelen);\n  hostname[namelen] = 0;\n\n  /* fill hostent */\n  h->addrs = &(h->addr);\n  h->aliases = NULL;\n  ret->h_name = (char*)hostname;\n  ret->h_aliases = &(h->aliases);\n  ret->h_addrtype = AF_INET;\n  ret->h_length = sizeof(ip_addr_t);\n  ret->h_addr_list = (char**)&(h->addrs);\n\n  /* set result != NULL */\n  *result = ret;\n\n  /* return success */\n  return 0;\n}\n\n/**\n * Frees one or more addrinfo structures returned by getaddrinfo(), along with\n * any additional storage associated with those structures. If the ai_next field\n * of the structure is not null, the entire list of structures is freed.\n *\n * @param ai struct addrinfo to free\n */\nvoid\nlwip_freeaddrinfo(struct addrinfo *ai)\n{\n  struct addrinfo *next;\n\n  while (ai != NULL) {\n    next = ai->ai_next;\n    memp_free(MEMP_NETDB, ai);\n    ai = next;\n  }\n}\n\n/**\n * Translates the name of a service location (for example, a host name) and/or\n * a service name and returns a set of socket addresses and associated\n * information to be used in creating a socket with which to address the\n * specified service.\n * Memory for the result is allocated internally and must be freed by calling\n * lwip_freeaddrinfo()!\n *\n * Due to a limitation in dns_gethostbyname, only the first address of a\n * host is returned.\n * Also, service names are not supported (only port numbers)!\n *\n * @param nodename descriptive name or address string of the host\n *                 (may be NULL -> local address)\n * @param servname port number as string of NULL \n * @param hints structure containing input values that set socktype and protocol\n * @param res pointer to a pointer where to store the result (set to NULL on failure)\n * @return 0 on success, non-zero on failure\n */\nint\nlwip_getaddrinfo(const char *nodename, const char *servname,\n       const struct addrinfo *hints, struct addrinfo **res)\n{\n  err_t err;\n  ip_addr_t addr;\n  struct addrinfo *ai;\n  struct sockaddr_in *sa = NULL;\n  int port_nr = 0;\n  size_t total_size;\n  size_t namelen = 0;\n\n  if (res == NULL) {\n    return EAI_FAIL;\n  }\n  *res = NULL;\n  if ((nodename == NULL) && (servname == NULL)) {\n    return EAI_NONAME;\n  }\n\n  if (servname != NULL) {\n    /* service name specified: convert to port number\n     * @todo?: currently, only ASCII integers (port numbers) are supported! */\n    port_nr = atoi(servname);\n    if ((port_nr <= 0) || (port_nr > 0xffff)) {\n      return EAI_SERVICE;\n    }\n  }\n\n  if (nodename != NULL) {\n    /* service location specified, try to resolve */\n    err = netconn_gethostbyname(nodename, &addr);\n    if (err != ERR_OK) {\n      return EAI_FAIL;\n    }\n  } else {\n    /* service location specified, use loopback address */\n    ip_addr_set_loopback(&addr);\n  }\n\n  total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);\n  if (nodename != NULL) {\n    namelen = strlen(nodename);\n    LWIP_ASSERT(\"namelen is too long\", (namelen + 1) <= (mem_size_t)-1);\n    total_size += namelen + 1;\n  }\n  /* If this fails, please report to lwip-devel! :-) */\n  LWIP_ASSERT(\"total_size <= NETDB_ELEM_SIZE: please report this!\",\n    total_size <= NETDB_ELEM_SIZE);\n  ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);\n  if (ai == NULL) {\n    goto memerr;\n  }\n  memset(ai, 0, total_size);\n  sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));\n  /* set up sockaddr */\n  inet_addr_from_ipaddr(&sa->sin_addr, &addr);\n  sa->sin_family = AF_INET;\n  sa->sin_len = sizeof(struct sockaddr_in);\n  sa->sin_port = htons((u16_t)port_nr);\n\n  /* set up addrinfo */\n  ai->ai_family = AF_INET;\n  if (hints != NULL) {\n    /* copy socktype & protocol from hints if specified */\n    ai->ai_socktype = hints->ai_socktype;\n    ai->ai_protocol = hints->ai_protocol;\n  }\n  if (nodename != NULL) {\n    /* copy nodename to canonname if specified */\n    ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));\n    MEMCPY(ai->ai_canonname, nodename, namelen);\n    ai->ai_canonname[namelen] = 0;\n  }\n  ai->ai_addrlen = sizeof(struct sockaddr_in);\n  ai->ai_addr = (struct sockaddr*)sa;\n\n  *res = ai;\n\n  return 0;\nmemerr:\n  if (ai != NULL) {\n    memp_free(MEMP_NETDB, ai);\n  }\n  return EAI_MEMORY;\n}\n\n#endif /* LWIP_DNS && LWIP_SOCKET */\n"
  },
  {
    "path": "app/lwip/api/netifapi.c",
    "content": "/**\n * @file\n * Network Interface Sequential API module\n *\n */\n\n/*\n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/netifapi.h\"\n#include \"lwip/tcpip.h\"\n\n/**\n * Call netif_add() inside the tcpip_thread context.\n */\nvoid\ndo_netifapi_netif_add(struct netifapi_msg_msg *msg)\n{\n  if (!netif_add( msg->netif,\n                  msg->msg.add.ipaddr,\n                  msg->msg.add.netmask,\n                  msg->msg.add.gw,\n                  msg->msg.add.state,\n                  msg->msg.add.init,\n                  msg->msg.add.input)) {\n    msg->err = ERR_IF;\n  } else {\n    msg->err = ERR_OK;\n  }\n  TCPIP_NETIFAPI_ACK(msg);\n}\n\n/**\n * Call netif_set_addr() inside the tcpip_thread context.\n */\nvoid\ndo_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)\n{\n  netif_set_addr( msg->netif,\n                  msg->msg.add.ipaddr,\n                  msg->msg.add.netmask,\n                  msg->msg.add.gw);\n  msg->err = ERR_OK;\n  TCPIP_NETIFAPI_ACK(msg);\n}\n\n/**\n * Call the \"errtfunc\" (or the \"voidfunc\" if \"errtfunc\" is NULL) inside the\n * tcpip_thread context.\n */\nvoid\ndo_netifapi_netif_common(struct netifapi_msg_msg *msg)\n{\n  if (msg->msg.common.errtfunc != NULL) {\n    msg->err = msg->msg.common.errtfunc(msg->netif);\n  } else {\n    msg->err = ERR_OK;\n    msg->msg.common.voidfunc(msg->netif);\n  }\n  TCPIP_NETIFAPI_ACK(msg);\n}\n\n/**\n * Call netif_add() in a thread-safe way by running that function inside the\n * tcpip_thread context.\n *\n * @note for params @see netif_add()\n */\nerr_t\nnetifapi_netif_add(struct netif *netif,\n                   ip_addr_t *ipaddr,\n                   ip_addr_t *netmask,\n                   ip_addr_t *gw,\n                   void *state,\n                   netif_init_fn init,\n                   netif_input_fn input)\n{\n  struct netifapi_msg msg;\n  msg.function = do_netifapi_netif_add;\n  msg.msg.netif = netif;\n  msg.msg.msg.add.ipaddr  = ipaddr;\n  msg.msg.msg.add.netmask = netmask;\n  msg.msg.msg.add.gw      = gw;\n  msg.msg.msg.add.state   = state;\n  msg.msg.msg.add.init    = init;\n  msg.msg.msg.add.input   = input;\n  TCPIP_NETIFAPI(&msg);\n  return msg.msg.err;\n}\n\n/**\n * Call netif_set_addr() in a thread-safe way by running that function inside the\n * tcpip_thread context.\n *\n * @note for params @see netif_set_addr()\n */\nerr_t\nnetifapi_netif_set_addr(struct netif *netif,\n                        ip_addr_t *ipaddr,\n                        ip_addr_t *netmask,\n                        ip_addr_t *gw)\n{\n  struct netifapi_msg msg;\n  msg.function = do_netifapi_netif_set_addr;\n  msg.msg.netif = netif;\n  msg.msg.msg.add.ipaddr  = ipaddr;\n  msg.msg.msg.add.netmask = netmask;\n  msg.msg.msg.add.gw      = gw;\n  TCPIP_NETIFAPI(&msg);\n  return msg.msg.err;\n}\n\n/**\n * call the \"errtfunc\" (or the \"voidfunc\" if \"errtfunc\" is NULL) in a thread-safe\n * way by running that function inside the tcpip_thread context.\n *\n * @note use only for functions where there is only \"netif\" parameter.\n */\nerr_t\nnetifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,\n                       netifapi_errt_fn errtfunc)\n{\n  struct netifapi_msg msg;\n  msg.function = do_netifapi_netif_common;\n  msg.msg.netif = netif;\n  msg.msg.msg.common.voidfunc = voidfunc;\n  msg.msg.msg.common.errtfunc = errtfunc;\n  TCPIP_NETIFAPI(&msg);\n  return msg.msg.err;\n}\n\n#endif /* LWIP_NETIF_API */\n"
  },
  {
    "path": "app/lwip/api/sockets.c",
    "content": "/**\n * @file\n * Sockets BSD-Like API module\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/sockets.h\"\n#include \"lwip/api.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/igmp.h\"\n#include \"lwip/inet.h\"\n#include \"lwip/tcp.h\"\n#include \"lwip/raw.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/tcpip.h\"\n#include \"lwip/pbuf.h\"\n#if LWIP_CHECKSUM_ON_COPY\n#include \"lwip/inet_chksum.h\"\n#endif\n\n#include <string.h>\n\n#define NUM_SOCKETS MEMP_NUM_NETCONN\n\n/** Contains all internal pointers and states used for a socket */\nstruct lwip_sock {\n  /** sockets currently are built on netconns, each socket has one netconn */\n  struct netconn *conn;\n  /** data that was left from the previous read */\n  void *lastdata;\n  /** offset in the data that was left from the previous read */\n  u16_t lastoffset;\n  /** number of times data was received, set by event_callback(),\n      tested by the receive and select functions */\n  s16_t rcvevent;\n  /** number of times data was ACKed (free send buffer), set by event_callback(),\n      tested by select */\n  u16_t sendevent;\n  /** error happened for this socket, set by event_callback(), tested by select */\n  u16_t errevent; \n  /** last error that occurred on this socket */\n  int err;\n  /** counter of how many threads are waiting for this socket using select */\n  int select_waiting;\n};\n\n/** Description for a task waiting in select */\nstruct lwip_select_cb {\n  /** Pointer to the next waiting task */\n  struct lwip_select_cb *next;\n  /** Pointer to the previous waiting task */\n  struct lwip_select_cb *prev;\n  /** readset passed to select */\n  fd_set *readset;\n  /** writeset passed to select */\n  fd_set *writeset;\n  /** unimplemented: exceptset passed to select */\n  fd_set *exceptset;\n  /** don't signal the same semaphore twice: set to 1 when signalled */\n  int sem_signalled;\n  /** semaphore to wake up a task waiting for select */\n  sys_sem_t sem;\n};\n\n/** This struct is used to pass data to the set/getsockopt_internal\n * functions running in tcpip_thread context (only a void* is allowed) */\nstruct lwip_setgetsockopt_data {\n  /** socket struct for which to change options */\n  struct lwip_sock *sock;\n#ifdef LWIP_DEBUG\n  /** socket index for which to change options */\n  int s;\n#endif /* LWIP_DEBUG */\n  /** level of the option to process */\n  int level;\n  /** name of the option to process */\n  int optname;\n  /** set: value to set the option to\n    * get: value of the option is stored here */\n  void *optval;\n  /** size of *optval */\n  socklen_t *optlen;\n  /** if an error occures, it is temporarily stored here */\n  err_t err;\n};\n\n/** The global array of available sockets */\nstatic struct lwip_sock sockets[NUM_SOCKETS];\n/** The global list of tasks waiting for select */\nstatic struct lwip_select_cb *select_cb_list;\n/** This counter is increased from lwip_select when the list is chagned\n    and checked in event_callback to see if it has changed. */\nstatic volatile int select_cb_ctr;\n\n/** Table to quickly map an lwIP error (err_t) to a socket error\n  * by using -err as an index */\nstatic const int err_to_errno_table[] = {\n  0,             /* ERR_OK          0      No error, everything OK. */\n  ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */\n  ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */\n  EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */\n  EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */\n  EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */\n  EINVAL,        /* ERR_VAL        -6      Illegal value.           */\n  EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */\n  ECONNABORTED,  /* ERR_ABRT       -8      Connection aborted.      */\n  ECONNRESET,    /* ERR_RST        -9      Connection reset.        */\n  ESHUTDOWN,     /* ERR_CLSD       -10     Connection closed.       */\n  ENOTCONN,      /* ERR_CONN       -11     Not connected.           */\n  EIO,           /* ERR_ARG        -12     Illegal argument.        */\n  EADDRINUSE,    /* ERR_USE        -13     Address in use.          */\n  -1,            /* ERR_IF         -14     Low-level netif error    */\n  -1,            /* ERR_ISCONN     -15     Already connected.       */\n};\n\n#define ERR_TO_ERRNO_TABLE_SIZE \\\n  (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))\n\n#define err_to_errno(err) \\\n  ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \\\n    err_to_errno_table[-(err)] : EIO)\n\n#ifdef ERRNO\n#ifndef set_errno\n#define set_errno(err) errno = (err)\n#endif\n#else /* ERRNO */\n#define set_errno(err)\n#endif /* ERRNO */\n\n#define sock_set_errno(sk, e) do { \\\n  sk->err = (e); \\\n  set_errno(sk->err); \\\n} while (0)\n\n/* Forward delcaration of some functions */\nstatic void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);\nstatic void lwip_getsockopt_internal(void *arg);\nstatic void lwip_setsockopt_internal(void *arg);\n\n/**\n * Initialize this module. This function has to be called before any other\n * functions in this module!\n */\nvoid\nlwip_socket_init(void)\n{\n}\n\n/**\n * Map a externally used socket index to the internal socket representation.\n *\n * @param s externally used socket index\n * @return struct lwip_sock for the socket or NULL if not found\n */\nstatic struct lwip_sock *\nget_socket(int s)\n{\n  struct lwip_sock *sock;\n\n  if ((s < 0) || (s >= NUM_SOCKETS)) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"get_socket(%d): invalid\\n\", s));\n    set_errno(EBADF);\n    return NULL;\n  }\n\n  sock = &sockets[s];\n\n  if (!sock->conn) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"get_socket(%d): not active\\n\", s));\n    set_errno(EBADF);\n    return NULL;\n  }\n\n  return sock;\n}\n\n/**\n * Same as get_socket but doesn't set errno\n *\n * @param s externally used socket index\n * @return struct lwip_sock for the socket or NULL if not found\n */\nstatic struct lwip_sock *\ntryget_socket(int s)\n{\n  if ((s < 0) || (s >= NUM_SOCKETS)) {\n    return NULL;\n  }\n  if (!sockets[s].conn) {\n    return NULL;\n  }\n  return &sockets[s];\n}\n\n/**\n * Allocate a new socket for a given netconn.\n *\n * @param newconn the netconn for which to allocate a socket\n * @param accepted 1 if socket has been created by accept(),\n *                 0 if socket has been created by socket()\n * @return the index of the new socket; -1 on error\n */\nstatic int\nalloc_socket(struct netconn *newconn, int accepted)\n{\n  int i;\n  SYS_ARCH_DECL_PROTECT(lev);\n\n  /* allocate a new socket identifier */\n  for (i = 0; i < NUM_SOCKETS; ++i) {\n    /* Protect socket array */\n    SYS_ARCH_PROTECT(lev);\n    if (!sockets[i].conn) {\n      sockets[i].conn       = newconn;\n      /* The socket is not yet known to anyone, so no need to protect\n         after having marked it as used. */\n      SYS_ARCH_UNPROTECT(lev);\n      sockets[i].lastdata   = NULL;\n      sockets[i].lastoffset = 0;\n      sockets[i].rcvevent   = 0;\n      /* TCP sendbuf is empty, but the socket is not yet writable until connected\n       * (unless it has been created by accept()). */\n      sockets[i].sendevent  = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);\n      sockets[i].errevent   = 0;\n      sockets[i].err        = 0;\n      sockets[i].select_waiting = 0;\n      return i;\n    }\n    SYS_ARCH_UNPROTECT(lev);\n  }\n  return -1;\n}\n\n/** Free a socket. The socket's netconn must have been\n * delete before!\n *\n * @param sock the socket to free\n * @param is_tcp != 0 for TCP sockets, used to free lastdata\n */\nstatic void\nfree_socket(struct lwip_sock *sock, int is_tcp)\n{\n  void *lastdata;\n  SYS_ARCH_DECL_PROTECT(lev);\n\n  lastdata         = sock->lastdata;\n  sock->lastdata   = NULL;\n  sock->lastoffset = 0;\n  sock->err        = 0;\n\n  /* Protect socket array */\n  SYS_ARCH_PROTECT(lev);\n  sock->conn       = NULL;\n  SYS_ARCH_UNPROTECT(lev);\n  /* don't use 'sock' after this line, as another task might have allocated it */\n\n  if (lastdata != NULL) {\n    if (is_tcp) {\n      pbuf_free((struct pbuf *)lastdata);\n    } else {\n      netbuf_delete((struct netbuf *)lastdata);\n    }\n  }\n}\n\n/* Below this, the well-known socket functions are implemented.\n * Use google.com or opengroup.org to get a good description :-)\n *\n * Exceptions are documented!\n */\n\nint\nlwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)\n{\n  struct lwip_sock *sock, *nsock;\n  struct netconn *newconn;\n  ip_addr_t naddr;\n  u16_t port;\n  int newsock;\n  struct sockaddr_in sin;\n  err_t err;\n  SYS_ARCH_DECL_PROTECT(lev);\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_accept(%d)...\\n\", s));\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_accept(%d): returning EWOULDBLOCK\\n\", s));\n    sock_set_errno(sock, EWOULDBLOCK);\n    return -1;\n  }\n\n  /* wait for a new connection */\n  err = netconn_accept(sock->conn, &newconn);\n  if (err != ERR_OK) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_accept(%d): netconn_acept failed, err=%d\\n\", s, err));\n    sock_set_errno(sock, err_to_errno(err));\n    return -1;\n  }\n  LWIP_ASSERT(\"newconn != NULL\", newconn != NULL);\n  /* Prevent automatic window updates, we do this on our own! */\n  netconn_set_noautorecved(newconn, 1);\n\n  /* get the IP address and port of the remote host */\n  err = netconn_peer(newconn, &naddr, &port);\n  if (err != ERR_OK) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_accept(%d): netconn_peer failed, err=%d\\n\", s, err));\n    netconn_delete(newconn);\n    sock_set_errno(sock, err_to_errno(err));\n    return -1;\n  }\n\n  /* Note that POSIX only requires us to check addr is non-NULL. addrlen must\n   * not be NULL if addr is valid.\n   */\n  if (NULL != addr) {\n    LWIP_ASSERT(\"addr valid but addrlen NULL\", addrlen != NULL);\n    memset(&sin, 0, sizeof(sin));\n    sin.sin_len = sizeof(sin);\n    sin.sin_family = AF_INET;\n    sin.sin_port = htons(port);\n    inet_addr_from_ipaddr(&sin.sin_addr, &naddr);\n\n    if (*addrlen > sizeof(sin))\n      *addrlen = sizeof(sin);\n\n    MEMCPY(addr, &sin, *addrlen);\n  }\n\n  newsock = alloc_socket(newconn, 1);\n  if (newsock == -1) {\n    netconn_delete(newconn);\n    sock_set_errno(sock, ENFILE);\n    return -1;\n  }\n  LWIP_ASSERT(\"invalid socket index\", (newsock >= 0) && (newsock < NUM_SOCKETS));\n  LWIP_ASSERT(\"newconn->callback == event_callback\", newconn->callback == event_callback);\n  nsock = &sockets[newsock];\n\n  /* See event_callback: If data comes in right away after an accept, even\n   * though the server task might not have created a new socket yet.\n   * In that case, newconn->socket is counted down (newconn->socket--),\n   * so nsock->rcvevent is >= 1 here!\n   */\n  SYS_ARCH_PROTECT(lev);\n  nsock->rcvevent += (s16_t)(-1 - newconn->socket);\n  newconn->socket = newsock;\n  SYS_ARCH_UNPROTECT(lev);\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_accept(%d) returning new sock=%d addr=\", s, newsock));\n  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\" port=%\"U16_F\"\\n\", port));\n\n  sock_set_errno(sock, 0);\n  return newsock;\n}\n\nint\nlwip_bind(int s, const struct sockaddr *name, socklen_t namelen)\n{\n  struct lwip_sock *sock;\n  ip_addr_t local_addr;\n  u16_t local_port;\n  err_t err;\n  const struct sockaddr_in *name_in;\n\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  /* check size, familiy and alignment of 'name' */\n  LWIP_ERROR(\"lwip_bind: invalid address\", ((namelen == sizeof(struct sockaddr_in)) &&\n             ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),\n             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);\n  name_in = (const struct sockaddr_in *)(void*)name;\n\n  inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);\n  local_port = name_in->sin_port;\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_bind(%d, addr=\", s));\n  ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\" port=%\"U16_F\")\\n\", ntohs(local_port)));\n\n  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));\n\n  if (err != ERR_OK) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_bind(%d) failed, err=%d\\n\", s, err));\n    sock_set_errno(sock, err_to_errno(err));\n    return -1;\n  }\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_bind(%d) succeeded\\n\", s));\n  sock_set_errno(sock, 0);\n  return 0;\n}\n\nint\nlwip_close(int s)\n{\n  struct lwip_sock *sock;\n  int is_tcp = 0;\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_close(%d)\\n\", s));\n\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  if(sock->conn != NULL) {\n    is_tcp = netconn_type(sock->conn) == NETCONN_TCP;\n  } else {\n    LWIP_ASSERT(\"sock->lastdata == NULL\", sock->lastdata == NULL);\n  }\n\n  netconn_delete(sock->conn);\n\n  free_socket(sock, is_tcp);\n  set_errno(0);\n  return 0;\n}\n\nint\nlwip_connect(int s, const struct sockaddr *name, socklen_t namelen)\n{\n  struct lwip_sock *sock;\n  err_t err;\n  const struct sockaddr_in *name_in;\n\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  /* check size, familiy and alignment of 'name' */\n  LWIP_ERROR(\"lwip_connect: invalid address\", ((namelen == sizeof(struct sockaddr_in)) &&\n             ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),\n             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);\n  name_in = (const struct sockaddr_in *)(void*)name;\n\n  if (name_in->sin_family == AF_UNSPEC) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_connect(%d, AF_UNSPEC)\\n\", s));\n    err = netconn_disconnect(sock->conn);\n  } else {\n    ip_addr_t remote_addr;\n    u16_t remote_port;\n\n    inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);\n    remote_port = name_in->sin_port;\n\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_connect(%d, addr=\", s));\n    ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\" port=%\"U16_F\")\\n\", ntohs(remote_port)));\n\n    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));\n  }\n\n  if (err != ERR_OK) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_connect(%d) failed, err=%d\\n\", s, err));\n    sock_set_errno(sock, err_to_errno(err));\n    return -1;\n  }\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_connect(%d) succeeded\\n\", s));\n  sock_set_errno(sock, 0);\n  return 0;\n}\n\n/**\n * Set a socket into listen mode.\n * The socket may not have been used for another connection previously.\n *\n * @param s the socket to set to listening mode\n * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)\n * @return 0 on success, non-zero on failure\n */\nint\nlwip_listen(int s, int backlog)\n{\n  struct lwip_sock *sock;\n  err_t err;\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_listen(%d, backlog=%d)\\n\", s, backlog));\n\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  /* limit the \"backlog\" parameter to fit in an u8_t */\n  backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);\n\n  err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);\n\n  if (err != ERR_OK) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_listen(%d) failed, err=%d\\n\", s, err));\n    sock_set_errno(sock, err_to_errno(err));\n    return -1;\n  }\n\n  sock_set_errno(sock, 0);\n  return 0;\n}\n\nint\nlwip_recvfrom(int s, void *mem, size_t len, int flags,\n        struct sockaddr *from, socklen_t *fromlen)\n{\n  struct lwip_sock *sock;\n  void             *buf = NULL;\n  struct pbuf      *p;\n  u16_t            buflen, copylen;\n  int              off = 0;\n  ip_addr_t        *addr;\n  u16_t            port;\n  u8_t             done = 0;\n  err_t            err;\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom(%d, %p, %\"SZT_F\", 0x%x, ..)\\n\", s, mem, len, flags));\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  do {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom: top while sock->lastdata=%p\\n\", sock->lastdata));\n    /* Check if there is data left from the last recv operation. */\n    if (sock->lastdata) {\n      buf = sock->lastdata;\n    } else {\n      /* If this is non-blocking call, then check first */\n      if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && \n          (sock->rcvevent <= 0)) {\n        if (off > 0) {\n          /* update receive window */\n          netconn_recved(sock->conn, (u32_t)off);\n          /* already received data, return that */\n          sock_set_errno(sock, 0);\n          return off;\n        }\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom(%d): returning EWOULDBLOCK\\n\", s));\n        sock_set_errno(sock, EWOULDBLOCK);\n        return -1;\n      }\n\n      /* No data was left from the previous operation, so we try to get\n         some from the network. */\n      if (netconn_type(sock->conn) == NETCONN_TCP) {\n        err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);\n      } else {\n        err = netconn_recv(sock->conn, (struct netbuf **)&buf);\n      }\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom: netconn_recv err=%d, netbuf=%p\\n\",\n        err, buf));\n\n      if (err != ERR_OK) {\n        if (off > 0) {\n          /* update receive window */\n          netconn_recved(sock->conn, (u32_t)off);\n          /* already received data, return that */\n          sock_set_errno(sock, 0);\n          return off;\n        }\n        /* We should really do some error checking here. */\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom(%d): buf == NULL, error is \\\"%s\\\"!\\n\",\n          s, lwip_strerr(err)));\n        sock_set_errno(sock, err_to_errno(err));\n        if (err == ERR_CLSD) {\n          return 0;\n        } else {\n          return -1;\n        }\n      }\n      LWIP_ASSERT(\"buf != NULL\", buf != NULL);\n      sock->lastdata = buf;\n    }\n\n    if (netconn_type(sock->conn) == NETCONN_TCP) {\n      p = (struct pbuf *)buf;\n    } else {\n      p = ((struct netbuf *)buf)->p;\n    }\n    buflen = p->tot_len;\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom: buflen=%\"U16_F\" len=%\"SZT_F\" off=%d sock->lastoffset=%\"U16_F\"\\n\",\n      buflen, len, off, sock->lastoffset));\n\n    buflen -= sock->lastoffset;\n\n    if (len > buflen) {\n      copylen = buflen;\n    } else {\n      copylen = (u16_t)len;\n    }\n\n    /* copy the contents of the received buffer into\n    the supplied memory pointer mem */\n    pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);\n\n    off += copylen;\n\n    if (netconn_type(sock->conn) == NETCONN_TCP) {\n      LWIP_ASSERT(\"invalid copylen, len would underflow\", len >= copylen);\n      len -= copylen;\n      if ( (len <= 0) || \n           (p->flags & PBUF_FLAG_PUSH) || \n           (sock->rcvevent <= 0) || \n           ((flags & MSG_PEEK)!=0)) {\n        done = 1;\n      }\n    } else {\n      done = 1;\n    }\n\n    /* Check to see from where the data was.*/\n    if (done) {\n      ip_addr_t fromaddr;\n      if (from && fromlen) {\n        struct sockaddr_in sin;\n\n        if (netconn_type(sock->conn) == NETCONN_TCP) {\n          addr = &fromaddr;\n          netconn_getaddr(sock->conn, addr, &port, 0);\n        } else {\n          addr = netbuf_fromaddr((struct netbuf *)buf);\n          port = netbuf_fromport((struct netbuf *)buf);\n        }\n\n        memset(&sin, 0, sizeof(sin));\n        sin.sin_len = sizeof(sin);\n        sin.sin_family = AF_INET;\n        sin.sin_port = htons(port);\n        inet_addr_from_ipaddr(&sin.sin_addr, addr);\n\n        if (*fromlen > sizeof(sin)) {\n          *fromlen = sizeof(sin);\n        }\n\n        MEMCPY(from, &sin, *fromlen);\n\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom(%d): addr=\", s));\n        ip_addr_debug_print(SOCKETS_DEBUG, addr);\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\" port=%\"U16_F\" len=%d\\n\", port, off));\n      } else {\n#if SOCKETS_DEBUG\n        if (netconn_type(sock->conn) == NETCONN_TCP) {\n          addr = &fromaddr;\n          netconn_getaddr(sock->conn, addr, &port, 0);\n        } else {\n          addr = netbuf_fromaddr((struct netbuf *)buf);\n          port = netbuf_fromport((struct netbuf *)buf);\n        }\n\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom(%d): addr=\", s));\n        ip_addr_debug_print(SOCKETS_DEBUG, addr);\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\" port=%\"U16_F\" len=%d\\n\", port, off));\n#endif /*  SOCKETS_DEBUG */\n      }\n    }\n\n    /* If we don't peek the incoming message... */\n    if ((flags & MSG_PEEK) == 0) {\n      /* If this is a TCP socket, check if there is data left in the\n         buffer. If so, it should be saved in the sock structure for next\n         time around. */\n      if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {\n        sock->lastdata = buf;\n        sock->lastoffset += copylen;\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom: lastdata now netbuf=%p\\n\", buf));\n      } else {\n        sock->lastdata = NULL;\n        sock->lastoffset = 0;\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_recvfrom: deleting netbuf=%p\\n\", buf));\n        if (netconn_type(sock->conn) == NETCONN_TCP) {\n          pbuf_free((struct pbuf *)buf);\n        } else {\n          netbuf_delete((struct netbuf *)buf);\n        }\n      }\n    }\n  } while (!done);\n\n  if (off > 0) {\n    /* update receive window */\n    netconn_recved(sock->conn, (u32_t)off);\n  }\n  sock_set_errno(sock, 0);\n  return off;\n}\n\nint\nlwip_read(int s, void *mem, size_t len)\n{\n  return lwip_recvfrom(s, mem, len, 0, NULL, NULL);\n}\n\nint\nlwip_recv(int s, void *mem, size_t len, int flags)\n{\n  return lwip_recvfrom(s, mem, len, flags, NULL, NULL);\n}\n\nint\nlwip_send(int s, const void *data, size_t size, int flags)\n{\n  struct lwip_sock *sock;\n  err_t err;\n  u8_t write_flags;\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_send(%d, data=%p, size=%\"SZT_F\", flags=0x%x)\\n\",\n                              s, data, size, flags));\n\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  if (sock->conn->type != NETCONN_TCP) {\n#if (LWIP_UDP || LWIP_RAW)\n    return lwip_sendto(s, data, size, flags, NULL, 0);\n#else /* (LWIP_UDP || LWIP_RAW) */\n    sock_set_errno(sock, err_to_errno(ERR_ARG));\n    return -1;\n#endif /* (LWIP_UDP || LWIP_RAW) */\n  }\n\n  if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {\n    if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {\n      /* too much data to ever send nonblocking! */\n      sock_set_errno(sock, EMSGSIZE);\n      return -1;\n    }\n  }\n\n  write_flags = NETCONN_COPY |\n    ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |\n    ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);\n  err = netconn_write(sock->conn, data, size, write_flags);\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_send(%d) err=%d size=%\"SZT_F\"\\n\", s, err, size));\n  sock_set_errno(sock, err_to_errno(err));\n  return (err == ERR_OK ? (int)size : -1);\n}\n\nint\nlwip_sendto(int s, const void *data, size_t size, int flags,\n       const struct sockaddr *to, socklen_t tolen)\n{\n  struct lwip_sock *sock;\n  err_t err;\n  u16_t short_size;\n  const struct sockaddr_in *to_in;\n  u16_t remote_port;\n#if !LWIP_TCPIP_CORE_LOCKING\n  struct netbuf buf;\n#endif\n\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  if (sock->conn->type == NETCONN_TCP) {\n#if LWIP_TCP\n    return lwip_send(s, data, size, flags);\n#else /* LWIP_TCP */\n    LWIP_UNUSED_ARG(flags);\n    sock_set_errno(sock, err_to_errno(ERR_ARG));\n    return -1;\n#endif /* LWIP_TCP */\n  }\n\n  /* @todo: split into multiple sendto's? */\n  LWIP_ASSERT(\"lwip_sendto: size must fit in u16_t\", size <= 0xffff);\n  short_size = (u16_t)size;\n  LWIP_ERROR(\"lwip_sendto: invalid address\", (((to == NULL) && (tolen == 0)) ||\n             ((tolen == sizeof(struct sockaddr_in)) &&\n             ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),\n             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);\n  to_in = (const struct sockaddr_in *)(void*)to;\n\n#if LWIP_TCPIP_CORE_LOCKING\n  /* Should only be consider like a sample or a simple way to experiment this option (no check of \"to\" field...) */\n  {\n    struct pbuf* p;\n    ip_addr_t *remote_addr;\n\n#if LWIP_NETIF_TX_SINGLE_PBUF\n    p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);\n    if (p != NULL) {\n#if LWIP_CHECKSUM_ON_COPY\n      u16_t chksum = 0;\n      if (sock->conn->type != NETCONN_RAW) {\n        chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);\n      } else\n#endif /* LWIP_CHECKSUM_ON_COPY */\n      MEMCPY(p->payload, data, size);\n#else /* LWIP_NETIF_TX_SINGLE_PBUF */\n    p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);\n    if (p != NULL) {\n      p->payload = (void*)data;\n#endif /* LWIP_NETIF_TX_SINGLE_PBUF */\n\n      if (to_in != NULL) {\n        inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);\n        remote_port = ntohs(to_in->sin_port);\n      } else {\n        remote_addr = IP_ADDR_ANY;\n        remote_port = 0;\n      }\n\n      LOCK_TCPIP_CORE();\n      if (sock->conn->type == NETCONN_RAW) {\n        err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);\n      } else {\n#if LWIP_UDP\n#if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF\n        err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,\n          remote_addr, remote_port, 1, chksum);\n#else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */\n        err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,\n          remote_addr, remote_port);\n#endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */\n#else /* LWIP_UDP */\n        err = ERR_ARG;\n#endif /* LWIP_UDP */\n      }\n      UNLOCK_TCPIP_CORE();\n      \n      pbuf_free(p);\n    } else {\n      err = ERR_MEM;\n    }\n  }\n#else /* LWIP_TCPIP_CORE_LOCKING */\n  /* initialize a buffer */\n  buf.p = buf.ptr = NULL;\n#if LWIP_CHECKSUM_ON_COPY\n  buf.flags = 0;\n#endif /* LWIP_CHECKSUM_ON_COPY */\n  if (to) {\n    inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);\n    remote_port           = ntohs(to_in->sin_port);\n    netbuf_fromport(&buf) = remote_port;\n  } else {\n    remote_port           = 0;\n    ip_addr_set_any(&buf.addr);\n    netbuf_fromport(&buf) = 0;\n  }\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_sendto(%d, data=%p, short_size=%d\"U16_F\", flags=0x%x to=\",\n              s, data, short_size, flags));\n  ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\" port=%\"U16_F\"\\n\", remote_port));\n\n  /* make the buffer point to the data that should be sent */\n#if LWIP_NETIF_TX_SINGLE_PBUF\n  /* Allocate a new netbuf and copy the data into it. */\n  if (netbuf_alloc(&buf, short_size) == NULL) {\n    err = ERR_MEM;\n  } else {\n#if LWIP_CHECKSUM_ON_COPY\n    if (sock->conn->type != NETCONN_RAW) {\n      u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);\n      netbuf_set_chksum(&buf, chksum);\n      err = ERR_OK;\n    } else\n#endif /* LWIP_CHECKSUM_ON_COPY */\n    {\n      err = netbuf_take(&buf, data, short_size);\n    }\n  }\n#else /* LWIP_NETIF_TX_SINGLE_PBUF */\n  err = netbuf_ref(&buf, data, short_size);\n#endif /* LWIP_NETIF_TX_SINGLE_PBUF */\n  if (err == ERR_OK) {\n    /* send the data */\n    err = netconn_send(sock->conn, &buf);\n  }\n\n  /* deallocated the buffer */\n  netbuf_free(&buf);\n#endif /* LWIP_TCPIP_CORE_LOCKING */\n  sock_set_errno(sock, err_to_errno(err));\n  return (err == ERR_OK ? short_size : -1);\n}\n\nint\nlwip_socket(int domain, int type, int protocol)\n{\n  struct netconn *conn;\n  int i;\n\n  LWIP_UNUSED_ARG(domain);\n\n  /* create a netconn */\n  switch (type) {\n  case SOCK_RAW:\n    conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_socket(%s, SOCK_RAW, %d) = \",\n                                 domain == PF_INET ? \"PF_INET\" : \"UNKNOWN\", protocol));\n    break;\n  case SOCK_DGRAM:\n    conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?\n                 NETCONN_UDPLITE : NETCONN_UDP, event_callback);\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_socket(%s, SOCK_DGRAM, %d) = \",\n                                 domain == PF_INET ? \"PF_INET\" : \"UNKNOWN\", protocol));\n    break;\n  case SOCK_STREAM:\n    conn = netconn_new_with_callback(NETCONN_TCP, event_callback);\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_socket(%s, SOCK_STREAM, %d) = \",\n                                 domain == PF_INET ? \"PF_INET\" : \"UNKNOWN\", protocol));\n    if (conn != NULL) {\n      /* Prevent automatic window updates, we do this on our own! */\n      netconn_set_noautorecved(conn, 1);\n    }\n    break;\n  default:\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_socket(%d, %d/UNKNOWN, %d) = -1\\n\",\n                                 domain, type, protocol));\n    set_errno(EINVAL);\n    return -1;\n  }\n\n  if (!conn) {\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"-1 / ENOBUFS (could not create netconn)\\n\"));\n    set_errno(ENOBUFS);\n    return -1;\n  }\n\n  i = alloc_socket(conn, 0);\n\n  if (i == -1) {\n    netconn_delete(conn);\n    set_errno(ENFILE);\n    return -1;\n  }\n  conn->socket = i;\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"%d\\n\", i));\n  set_errno(0);\n  return i;\n}\n\nint\nlwip_write(int s, const void *data, size_t size)\n{\n  return lwip_send(s, data, size, 0);\n}\n\n/**\n * Go through the readset and writeset lists and see which socket of the sockets\n * set in the sets has events. On return, readset, writeset and exceptset have\n * the sockets enabled that had events.\n *\n * exceptset is not used for now!!!\n *\n * @param maxfdp1 the highest socket index in the sets\n * @param readset_in:    set of sockets to check for read events\n * @param writeset_in:   set of sockets to check for write events\n * @param exceptset_in:  set of sockets to check for error events\n * @param readset_out:   set of sockets that had read events\n * @param writeset_out:  set of sockets that had write events\n * @param exceptset_out: set os sockets that had error events\n * @return number of sockets that had events (read/write/exception) (>= 0)\n */\nstatic int\nlwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,\n             fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)\n{\n  int i, nready = 0;\n  fd_set lreadset, lwriteset, lexceptset;\n  struct lwip_sock *sock;\n  SYS_ARCH_DECL_PROTECT(lev);\n\n  FD_ZERO(&lreadset);\n  FD_ZERO(&lwriteset);\n  FD_ZERO(&lexceptset);\n\n  /* Go through each socket in each list to count number of sockets which\n     currently match */\n  for(i = 0; i < maxfdp1; i++) {\n    void* lastdata = NULL;\n    s16_t rcvevent = 0;\n    u16_t sendevent = 0;\n    u16_t errevent = 0;\n    /* First get the socket's status (protected)... */\n    SYS_ARCH_PROTECT(lev);\n    sock = tryget_socket(i);\n    if (sock != NULL) {\n      lastdata = sock->lastdata;\n      rcvevent = sock->rcvevent;\n      sendevent = sock->sendevent;\n      errevent = sock->errevent;\n    }\n    SYS_ARCH_UNPROTECT(lev);\n    /* ... then examine it: */\n    /* See if netconn of this socket is ready for read */\n    if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {\n      FD_SET(i, &lreadset);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_selscan: fd=%d ready for reading\\n\", i));\n      nready++;\n    }\n    /* See if netconn of this socket is ready for write */\n    if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {\n      FD_SET(i, &lwriteset);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_selscan: fd=%d ready for writing\\n\", i));\n      nready++;\n    }\n    /* See if netconn of this socket had an error */\n    if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {\n      FD_SET(i, &lexceptset);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_selscan: fd=%d ready for exception\\n\", i));\n      nready++;\n    }\n  }\n  /* copy local sets to the ones provided as arguments */\n  *readset_out = lreadset;\n  *writeset_out = lwriteset;\n  *exceptset_out = lexceptset;\n\n  LWIP_ASSERT(\"nready >= 0\", nready >= 0);\n  return nready;\n}\n\n/**\n * Processing exceptset is not yet implemented.\n */\nint\nlwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,\n            struct timeval *timeout)\n{\n  u32_t waitres = 0;\n  int nready;\n  fd_set lreadset, lwriteset, lexceptset;\n  u32_t msectimeout;\n  struct lwip_select_cb select_cb;\n  err_t err;\n  int i;\n  SYS_ARCH_DECL_PROTECT(lev);\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_select(%d, %p, %p, %p, tvsec=%\"S32_F\" tvusec=%\"S32_F\")\\n\",\n                  maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,\n                  timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,\n                  timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));\n\n  /* Go through each socket in each list to count number of sockets which\n     currently match */\n  nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);\n\n  /* If we don't have any current events, then suspend if we are supposed to */\n  if (!nready) {\n    if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_select: no timeout, returning 0\\n\"));\n      /* This is OK as the local fdsets are empty and nready is zero,\n         or we would have returned earlier. */\n      goto return_copy_fdsets;\n    }\n\n    /* None ready: add our semaphore to list:\n       We don't actually need any dynamic memory. Our entry on the\n       list is only valid while we are in this function, so it's ok\n       to use local variables. */\n\n    select_cb.next = NULL;\n    select_cb.prev = NULL;\n    select_cb.readset = readset;\n    select_cb.writeset = writeset;\n    select_cb.exceptset = exceptset;\n    select_cb.sem_signalled = 0;\n    err = sys_sem_new(&select_cb.sem, 0);\n    if (err != ERR_OK) {\n      /* failed to create semaphore */\n      set_errno(ENOMEM);\n      return -1;\n    }\n\n    /* Protect the select_cb_list */\n    SYS_ARCH_PROTECT(lev);\n\n    /* Put this select_cb on top of list */\n    select_cb.next = select_cb_list;\n    if (select_cb_list != NULL) {\n      select_cb_list->prev = &select_cb;\n    }\n    select_cb_list = &select_cb;\n    /* Increasing this counter tells even_callback that the list has changed. */\n    select_cb_ctr++;\n\n    /* Now we can safely unprotect */\n    SYS_ARCH_UNPROTECT(lev);\n\n    /* Increase select_waiting for each socket we are interested in */\n    for(i = 0; i < maxfdp1; i++) {\n      if ((readset && FD_ISSET(i, readset)) ||\n          (writeset && FD_ISSET(i, writeset)) ||\n          (exceptset && FD_ISSET(i, exceptset))) {\n        struct lwip_sock *sock = tryget_socket(i);\n        LWIP_ASSERT(\"sock != NULL\", sock != NULL);\n        SYS_ARCH_PROTECT(lev);\n        sock->select_waiting++;\n        LWIP_ASSERT(\"sock->select_waiting > 0\", sock->select_waiting > 0);\n        SYS_ARCH_UNPROTECT(lev);\n      }\n    }\n\n    /* Call lwip_selscan again: there could have been events between\n       the last scan (whithout us on the list) and putting us on the list! */\n    nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);\n    if (!nready) {\n      /* Still none ready, just wait to be woken */\n      if (timeout == 0) {\n        /* Wait forever */\n        msectimeout = 0;\n      } else {\n        msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));\n        if (msectimeout == 0) {\n          /* Wait 1ms at least (0 means wait forever) */\n          msectimeout = 1;\n        }\n      }\n\n      waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);\n    }\n    /* Increase select_waiting for each socket we are interested in */\n    for(i = 0; i < maxfdp1; i++) {\n      if ((readset && FD_ISSET(i, readset)) ||\n          (writeset && FD_ISSET(i, writeset)) ||\n          (exceptset && FD_ISSET(i, exceptset))) {\n        struct lwip_sock *sock = tryget_socket(i);\n        LWIP_ASSERT(\"sock != NULL\", sock != NULL);\n        SYS_ARCH_PROTECT(lev);\n        sock->select_waiting--;\n        LWIP_ASSERT(\"sock->select_waiting >= 0\", sock->select_waiting >= 0);\n        SYS_ARCH_UNPROTECT(lev);\n      }\n    }\n    /* Take us off the list */\n    SYS_ARCH_PROTECT(lev);\n    if (select_cb.next != NULL) {\n      select_cb.next->prev = select_cb.prev;\n    }\n    if (select_cb_list == &select_cb) {\n      LWIP_ASSERT(\"select_cb.prev == NULL\", select_cb.prev == NULL);\n      select_cb_list = select_cb.next;\n    } else {\n      LWIP_ASSERT(\"select_cb.prev != NULL\", select_cb.prev != NULL);\n      select_cb.prev->next = select_cb.next;\n    }\n    /* Increasing this counter tells even_callback that the list has changed. */\n    select_cb_ctr++;\n    SYS_ARCH_UNPROTECT(lev);\n\n    sys_sem_free(&select_cb.sem);\n    if (waitres == SYS_ARCH_TIMEOUT)  {\n      /* Timeout */\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_select: timeout expired\\n\"));\n      /* This is OK as the local fdsets are empty and nready is zero,\n         or we would have returned earlier. */\n      goto return_copy_fdsets;\n    }\n\n    /* See what's set */\n    nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);\n  }\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_select: nready=%d\\n\", nready));\nreturn_copy_fdsets:\n  set_errno(0);\n  if (readset) {\n    *readset = lreadset;\n  }\n  if (writeset) {\n    *writeset = lwriteset;\n  }\n  if (exceptset) {\n    *exceptset = lexceptset;\n  }\n\n\n  return nready;\n}\n\n/**\n * Callback registered in the netconn layer for each socket-netconn.\n * Processes recvevent (data available) and wakes up tasks waiting for select.\n */\nstatic void\nevent_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)\n{\n  int s;\n  struct lwip_sock *sock;\n  struct lwip_select_cb *scb;\n  int last_select_cb_ctr;\n  SYS_ARCH_DECL_PROTECT(lev);\n\n  LWIP_UNUSED_ARG(len);\n\n  /* Get socket */\n  if (conn) {\n    s = conn->socket;\n    if (s < 0) {\n      /* Data comes in right away after an accept, even though\n       * the server task might not have created a new socket yet.\n       * Just count down (or up) if that's the case and we\n       * will use the data later. Note that only receive events\n       * can happen before the new socket is set up. */\n      SYS_ARCH_PROTECT(lev);\n      if (conn->socket < 0) {\n        if (evt == NETCONN_EVT_RCVPLUS) {\n          conn->socket--;\n        }\n        SYS_ARCH_UNPROTECT(lev);\n        return;\n      }\n      s = conn->socket;\n      SYS_ARCH_UNPROTECT(lev);\n    }\n\n    sock = get_socket(s);\n    if (!sock) {\n      return;\n    }\n  } else {\n    return;\n  }\n\n  SYS_ARCH_PROTECT(lev);\n  /* Set event as required */\n  switch (evt) {\n    case NETCONN_EVT_RCVPLUS:\n      sock->rcvevent++;\n      break;\n    case NETCONN_EVT_RCVMINUS:\n      sock->rcvevent--;\n      break;\n    case NETCONN_EVT_SENDPLUS:\n      sock->sendevent = 1;\n      break;\n    case NETCONN_EVT_SENDMINUS:\n      sock->sendevent = 0;\n      break;\n    case NETCONN_EVT_ERROR:\n      sock->errevent = 1;\n      break;\n    default:\n      LWIP_ASSERT(\"unknown event\", 0);\n      break;\n  }\n\n  if (sock->select_waiting == 0) {\n    /* noone is waiting for this socket, no need to check select_cb_list */\n    SYS_ARCH_UNPROTECT(lev);\n    return;\n  }\n\n  /* Now decide if anyone is waiting for this socket */\n  /* NOTE: This code goes through the select_cb_list list multiple times\n     ONLY IF a select was actually waiting. We go through the list the number\n     of waiting select calls + 1. This list is expected to be small. */\n\n  /* At this point, SYS_ARCH is still protected! */\nagain:\n  for (scb = select_cb_list; scb != NULL; scb = scb->next) {\n    if (scb->sem_signalled == 0) {\n      /* semaphore not signalled yet */\n      int do_signal = 0;\n      /* Test this select call for our socket */\n      if (sock->rcvevent > 0) {\n        if (scb->readset && FD_ISSET(s, scb->readset)) {\n          do_signal = 1;\n        }\n      }\n      if (sock->sendevent != 0) {\n        if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {\n          do_signal = 1;\n        }\n      }\n      if (sock->errevent != 0) {\n        if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {\n          do_signal = 1;\n        }\n      }\n      if (do_signal) {\n        scb->sem_signalled = 1;\n        /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might\n           lead to the select thread taking itself off the list, invalidagin the semaphore. */\n        sys_sem_signal(&scb->sem);\n      }\n    }\n    /* unlock interrupts with each step */\n    last_select_cb_ctr = select_cb_ctr;\n    SYS_ARCH_UNPROTECT(lev);\n    /* this makes sure interrupt protection time is short */\n    SYS_ARCH_PROTECT(lev);\n    if (last_select_cb_ctr != select_cb_ctr) {\n      /* someone has changed select_cb_list, restart at the beginning */\n      goto again;\n    }\n  }\n  SYS_ARCH_UNPROTECT(lev);\n}\n\n/**\n * Unimplemented: Close one end of a full-duplex connection.\n * Currently, the full connection is closed.\n */\nint\nlwip_shutdown(int s, int how)\n{\n  struct lwip_sock *sock;\n  err_t err;\n  u8_t shut_rx = 0, shut_tx = 0;\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_shutdown(%d, how=%d)\\n\", s, how));\n\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  if (sock->conn != NULL) {\n    if (netconn_type(sock->conn) != NETCONN_TCP) {\n      sock_set_errno(sock, EOPNOTSUPP);\n      return EOPNOTSUPP;\n    }\n  } else {\n    sock_set_errno(sock, ENOTCONN);\n    return ENOTCONN;\n  }\n\n  if (how == SHUT_RD) {\n    shut_rx = 1;\n  } else if (how == SHUT_WR) {\n    shut_tx = 1;\n  } else if(how == SHUT_RDWR) {\n    shut_rx = 1;\n    shut_tx = 1;\n  } else {\n    sock_set_errno(sock, EINVAL);\n    return EINVAL;\n  }\n  err = netconn_shutdown(sock->conn, shut_rx, shut_tx);\n\n  sock_set_errno(sock, err_to_errno(err));\n  return (err == ERR_OK ? 0 : -1);\n}\n\nstatic int\nlwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)\n{\n  struct lwip_sock *sock;\n  struct sockaddr_in sin;\n  ip_addr_t naddr;\n\n  sock = get_socket(s);\n  if (!sock) {\n    return -1;\n  }\n\n  memset(&sin, 0, sizeof(sin));\n  sin.sin_len = sizeof(sin);\n  sin.sin_family = AF_INET;\n\n  /* get the IP address and port */\n  netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);\n\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getaddrname(%d, addr=\", s));\n  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);\n  LWIP_DEBUGF(SOCKETS_DEBUG, (\" port=%\"U16_F\")\\n\", sin.sin_port));\n\n  sin.sin_port = htons(sin.sin_port);\n  inet_addr_from_ipaddr(&sin.sin_addr, &naddr);\n\n  if (*namelen > sizeof(sin)) {\n    *namelen = sizeof(sin);\n  }\n\n  MEMCPY(name, &sin, *namelen);\n  sock_set_errno(sock, 0);\n  return 0;\n}\n\nint\nlwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)\n{\n  return lwip_getaddrname(s, name, namelen, 0);\n}\n\nint\nlwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)\n{\n  return lwip_getaddrname(s, name, namelen, 1);\n}\n\nint\nlwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)\n{\n  err_t err = ERR_OK;\n  struct lwip_sock *sock = get_socket(s);\n  struct lwip_setgetsockopt_data data;\n\n  if (!sock) {\n    return -1;\n  }\n\n  if ((NULL == optval) || (NULL == optlen)) {\n    sock_set_errno(sock, EFAULT);\n    return -1;\n  }\n\n  /* Do length and type checks for the various options first, to keep it readable. */\n  switch (level) {\n   \n/* Level: SOL_SOCKET */\n  case SOL_SOCKET:\n    switch (optname) {\n       \n    case SO_ACCEPTCONN:\n    case SO_BROADCAST:\n    /* UNIMPL case SO_DEBUG: */\n    /* UNIMPL case SO_DONTROUTE: */\n    case SO_ERROR:\n    case SO_KEEPALIVE:\n    /* UNIMPL case SO_CONTIMEO: */\n    /* UNIMPL case SO_SNDTIMEO: */\n#if LWIP_SO_RCVTIMEO\n    case SO_RCVTIMEO:\n#endif /* LWIP_SO_RCVTIMEO */\n#if LWIP_SO_RCVBUF\n    case SO_RCVBUF:\n#endif /* LWIP_SO_RCVBUF */\n    /* UNIMPL case SO_OOBINLINE: */\n    /* UNIMPL case SO_SNDBUF: */\n    /* UNIMPL case SO_RCVLOWAT: */\n    /* UNIMPL case SO_SNDLOWAT: */\n#if SO_REUSE\n    case SO_REUSEADDR:\n    case SO_REUSEPORT:\n#endif /* SO_REUSE */\n    case SO_TYPE:\n    /* UNIMPL case SO_USELOOPBACK: */\n      if (*optlen < sizeof(int)) {\n        err = EINVAL;\n      }\n      break;\n\n    case SO_NO_CHECK:\n      if (*optlen < sizeof(int)) {\n        err = EINVAL;\n      }\n#if LWIP_UDP\n      if ((sock->conn->type != NETCONN_UDP) ||\n          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {\n        /* this flag is only available for UDP, not for UDP lite */\n        err = EAFNOSUPPORT;\n      }\n#endif /* LWIP_UDP */\n      break;\n\n    default:\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\\n\",\n                                  s, optname));\n      err = ENOPROTOOPT;\n    }  /* switch (optname) */\n    break;\n                     \n/* Level: IPPROTO_IP */\n  case IPPROTO_IP:\n    switch (optname) {\n    /* UNIMPL case IP_HDRINCL: */\n    /* UNIMPL case IP_RCVDSTADDR: */\n    /* UNIMPL case IP_RCVIF: */\n    case IP_TTL:\n    case IP_TOS:\n      if (*optlen < sizeof(int)) {\n        err = EINVAL;\n      }\n      break;\n#if LWIP_IGMP\n    case IP_MULTICAST_TTL:\n      if (*optlen < sizeof(u8_t)) {\n        err = EINVAL;\n      }\n      break;\n    case IP_MULTICAST_IF:\n      if (*optlen < sizeof(struct in_addr)) {\n        err = EINVAL;\n      }\n      break;\n    case IP_MULTICAST_LOOP:\n      if (*optlen < sizeof(u8_t)) {\n        err = EINVAL;\n      }\n      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {\n        err = EAFNOSUPPORT;\n      }\n      break;\n#endif /* LWIP_IGMP */\n\n    default:\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\\n\",\n                                  s, optname));\n      err = ENOPROTOOPT;\n    }  /* switch (optname) */\n    break;\n         \n#if LWIP_TCP\n/* Level: IPPROTO_TCP */\n  case IPPROTO_TCP:\n    if (*optlen < sizeof(int)) {\n      err = EINVAL;\n      break;\n    }\n    \n    /* If this is no TCP socket, ignore any options. */\n    if (sock->conn->type != NETCONN_TCP)\n      return 0;\n\n    switch (optname) {\n    case TCP_NODELAY:\n    case TCP_KEEPALIVE:\n#if LWIP_TCP_KEEPALIVE\n    case TCP_KEEPIDLE:\n    case TCP_KEEPINTVL:\n    case TCP_KEEPCNT:\n#endif /* LWIP_TCP_KEEPALIVE */\n      break;\n       \n    default:\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\\n\",\n                                  s, optname));\n      err = ENOPROTOOPT;\n    }  /* switch (optname) */\n    break;\n#endif /* LWIP_TCP */\n#if LWIP_UDP && LWIP_UDPLITE\n/* Level: IPPROTO_UDPLITE */\n  case IPPROTO_UDPLITE:\n    if (*optlen < sizeof(int)) {\n      err = EINVAL;\n      break;\n    }\n    \n    /* If this is no UDP lite socket, ignore any options. */\n    if (sock->conn->type != NETCONN_UDPLITE) {\n      return 0;\n    }\n\n    switch (optname) {\n    case UDPLITE_SEND_CSCOV:\n    case UDPLITE_RECV_CSCOV:\n      break;\n       \n    default:\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\\n\",\n                                  s, optname));\n      err = ENOPROTOOPT;\n    }  /* switch (optname) */\n    break;\n#endif /* LWIP_UDP && LWIP_UDPLITE*/\n/* UNDEFINED LEVEL */\n  default:\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\\n\",\n                                  s, level, optname));\n      err = ENOPROTOOPT;\n  }  /* switch */\n\n   \n  if (err != ERR_OK) {\n    sock_set_errno(sock, err);\n    return -1;\n  }\n\n  /* Now do the actual option processing */\n  data.sock = sock;\n#ifdef LWIP_DEBUG\n  data.s = s;\n#endif /* LWIP_DEBUG */\n  data.level = level;\n  data.optname = optname;\n  data.optval = optval;\n  data.optlen = optlen;\n  data.err = err;\n  tcpip_callback(lwip_getsockopt_internal, &data);\n  sys_arch_sem_wait(&sock->conn->op_completed, 0);\n  /* maybe lwip_getsockopt_internal has changed err */\n  err = data.err;\n\n  sock_set_errno(sock, err);\n  return err ? -1 : 0;\n}\n\nstatic void\nlwip_getsockopt_internal(void *arg)\n{\n  struct lwip_sock *sock;\n#ifdef LWIP_DEBUG\n  int s;\n#endif /* LWIP_DEBUG */\n  int level, optname;\n  void *optval;\n  struct lwip_setgetsockopt_data *data;\n\n  LWIP_ASSERT(\"arg != NULL\", arg != NULL);\n\n  data = (struct lwip_setgetsockopt_data*)arg;\n  sock = data->sock;\n#ifdef LWIP_DEBUG\n  s = data->s;\n#endif /* LWIP_DEBUG */\n  level = data->level;\n  optname = data->optname;\n  optval = data->optval;\n\n  switch (level) {\n\n/* Level: SOL_SOCKET */\n  case SOL_SOCKET:\n    switch (optname) {\n\n    /* The option flags */\n    case SO_ACCEPTCONN:\n    case SO_BROADCAST:\n    /* UNIMPL case SO_DEBUG: */\n    /* UNIMPL case SO_DONTROUTE: */\n    case SO_KEEPALIVE:\n    /* UNIMPL case SO_OOBINCLUDE: */\n#if SO_REUSE\n    case SO_REUSEADDR:\n    case SO_REUSEPORT:\n#endif /* SO_REUSE */\n    /*case SO_USELOOPBACK: UNIMPL */\n      *(int*)optval = sock->conn->pcb.ip->so_options & optname;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\\n\",\n                                  s, optname, (*(int*)optval?\"on\":\"off\")));\n      break;\n\n    case SO_TYPE:\n      switch (NETCONNTYPE_GROUP(sock->conn->type)) {\n      case NETCONN_RAW:\n        *(int*)optval = SOCK_RAW;\n        break;\n      case NETCONN_TCP:\n        *(int*)optval = SOCK_STREAM;\n        break;\n      case NETCONN_UDP:\n        *(int*)optval = SOCK_DGRAM;\n        break;\n      default: /* unrecognized socket type */\n        *(int*)optval = sock->conn->type;\n        LWIP_DEBUGF(SOCKETS_DEBUG,\n                    (\"lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\\n\",\n                    s, *(int *)optval));\n      }  /* switch (sock->conn->type) */\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n\n    case SO_ERROR:\n      /* only overwrite ERR_OK or tempoary errors */\n      if ((sock->err == 0) || (sock->err == EINPROGRESS)) {\n        sock_set_errno(sock, err_to_errno(sock->conn->last_err));\n      } \n      *(int *)optval = sock->err;\n      sock->err = 0;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n\n#if LWIP_SO_RCVTIMEO\n    case SO_RCVTIMEO:\n      *(int *)optval = netconn_get_recvtimeout(sock->conn);\n      break;\n#endif /* LWIP_SO_RCVTIMEO */\n#if LWIP_SO_RCVBUF\n    case SO_RCVBUF:\n      *(int *)optval = netconn_get_recvbufsize(sock->conn);\n      break;\n#endif /* LWIP_SO_RCVBUF */\n#if LWIP_UDP\n    case SO_NO_CHECK:\n      *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;\n      break;\n#endif /* LWIP_UDP*/\n    default:\n      LWIP_ASSERT(\"unhandled optname\", 0);\n      break;\n    }  /* switch (optname) */\n    break;\n\n/* Level: IPPROTO_IP */\n  case IPPROTO_IP:\n    switch (optname) {\n    case IP_TTL:\n      *(int*)optval = sock->conn->pcb.ip->ttl;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n    case IP_TOS:\n      *(int*)optval = sock->conn->pcb.ip->tos;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n#if LWIP_IGMP\n    case IP_MULTICAST_TTL:\n      *(u8_t*)optval = sock->conn->pcb.ip->ttl;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n    case IP_MULTICAST_IF:\n      inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%\"X32_F\"\\n\",\n                  s, *(u32_t *)optval));\n      break;\n    case IP_MULTICAST_LOOP:\n      if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {\n        *(u8_t*)optval = 1;\n      } else {\n        *(u8_t*)optval = 0;\n      }\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n#endif /* LWIP_IGMP */\n    default:\n      LWIP_ASSERT(\"unhandled optname\", 0);\n      break;\n    }  /* switch (optname) */\n    break;\n\n#if LWIP_TCP\n/* Level: IPPROTO_TCP */\n  case IPPROTO_TCP:\n    switch (optname) {\n    case TCP_NODELAY:\n      *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\\n\",\n                  s, (*(int*)optval)?\"on\":\"off\") );\n      break;\n    case TCP_KEEPALIVE:\n      *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n\n#if LWIP_TCP_KEEPALIVE\n    case TCP_KEEPIDLE:\n      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n    case TCP_KEEPINTVL:\n      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n    case TCP_KEEPCNT:\n      *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\\n\",\n                  s, *(int *)optval));\n      break;\n#endif /* LWIP_TCP_KEEPALIVE */\n    default:\n      LWIP_ASSERT(\"unhandled optname\", 0);\n      break;\n    }  /* switch (optname) */\n    break;\n#endif /* LWIP_TCP */\n#if LWIP_UDP && LWIP_UDPLITE\n  /* Level: IPPROTO_UDPLITE */\n  case IPPROTO_UDPLITE:\n    switch (optname) {\n    case UDPLITE_SEND_CSCOV:\n      *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\\n\",\n                  s, (*(int*)optval)) );\n      break;\n    case UDPLITE_RECV_CSCOV:\n      *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\\n\",\n                  s, (*(int*)optval)) );\n      break;\n    default:\n      LWIP_ASSERT(\"unhandled optname\", 0);\n      break;\n    }  /* switch (optname) */\n    break;\n#endif /* LWIP_UDP */\n  default:\n    LWIP_ASSERT(\"unhandled level\", 0);\n    break;\n  } /* switch (level) */\n  sys_sem_signal(&sock->conn->op_completed);\n}\n\nint\nlwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)\n{\n  struct lwip_sock *sock = get_socket(s);\n  err_t err = ERR_OK;\n  struct lwip_setgetsockopt_data data;\n\n  if (!sock) {\n    return -1;\n  }\n\n  if (NULL == optval) {\n    sock_set_errno(sock, EFAULT);\n    return -1;\n  }\n\n  /* Do length and type checks for the various options first, to keep it readable. */\n  switch (level) {\n\n/* Level: SOL_SOCKET */\n  case SOL_SOCKET:\n    switch (optname) {\n\n    case SO_BROADCAST:\n    /* UNIMPL case SO_DEBUG: */\n    /* UNIMPL case SO_DONTROUTE: */\n    case SO_KEEPALIVE:\n    /* UNIMPL case case SO_CONTIMEO: */\n    /* UNIMPL case case SO_SNDTIMEO: */\n#if LWIP_SO_RCVTIMEO\n    case SO_RCVTIMEO:\n#endif /* LWIP_SO_RCVTIMEO */\n#if LWIP_SO_RCVBUF\n    case SO_RCVBUF:\n#endif /* LWIP_SO_RCVBUF */\n    /* UNIMPL case SO_OOBINLINE: */\n    /* UNIMPL case SO_SNDBUF: */\n    /* UNIMPL case SO_RCVLOWAT: */\n    /* UNIMPL case SO_SNDLOWAT: */\n#if SO_REUSE\n    case SO_REUSEADDR:\n    case SO_REUSEPORT:\n#endif /* SO_REUSE */\n    /* UNIMPL case SO_USELOOPBACK: */\n      if (optlen < sizeof(int)) {\n        err = EINVAL;\n      }\n      break;\n    case SO_NO_CHECK:\n      if (optlen < sizeof(int)) {\n        err = EINVAL;\n      }\n#if LWIP_UDP\n      if ((sock->conn->type != NETCONN_UDP) ||\n          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {\n        /* this flag is only available for UDP, not for UDP lite */\n        err = EAFNOSUPPORT;\n      }\n#endif /* LWIP_UDP */\n      break;\n    default:\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\\n\",\n                  s, optname));\n      err = ENOPROTOOPT;\n    }  /* switch (optname) */\n    break;\n\n/* Level: IPPROTO_IP */\n  case IPPROTO_IP:\n    switch (optname) {\n    /* UNIMPL case IP_HDRINCL: */\n    /* UNIMPL case IP_RCVDSTADDR: */\n    /* UNIMPL case IP_RCVIF: */\n    case IP_TTL:\n    case IP_TOS:\n      if (optlen < sizeof(int)) {\n        err = EINVAL;\n      }\n      break;\n#if LWIP_IGMP\n    case IP_MULTICAST_TTL:\n      if (optlen < sizeof(u8_t)) {\n        err = EINVAL;\n      }\n      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {\n        err = EAFNOSUPPORT;\n      }\n      break;\n    case IP_MULTICAST_IF:\n      if (optlen < sizeof(struct in_addr)) {\n        err = EINVAL;\n      }\n      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {\n        err = EAFNOSUPPORT;\n      }\n      break;\n    case IP_MULTICAST_LOOP:\n      if (optlen < sizeof(u8_t)) {\n        err = EINVAL;\n      }\n      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {\n        err = EAFNOSUPPORT;\n      }\n      break;\n    case IP_ADD_MEMBERSHIP:\n    case IP_DROP_MEMBERSHIP:\n      if (optlen < sizeof(struct ip_mreq)) {\n        err = EINVAL;\n      }\n      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {\n        err = EAFNOSUPPORT;\n      }\n      break;\n#endif /* LWIP_IGMP */\n      default:\n        LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\\n\",\n                    s, optname));\n        err = ENOPROTOOPT;\n    }  /* switch (optname) */\n    break;\n\n#if LWIP_TCP\n/* Level: IPPROTO_TCP */\n  case IPPROTO_TCP:\n    if (optlen < sizeof(int)) {\n      err = EINVAL;\n      break;\n    }\n\n    /* If this is no TCP socket, ignore any options. */\n    if (sock->conn->type != NETCONN_TCP)\n      return 0;\n\n    switch (optname) {\n    case TCP_NODELAY:\n    case TCP_KEEPALIVE:\n#if LWIP_TCP_KEEPALIVE\n    case TCP_KEEPIDLE:\n    case TCP_KEEPINTVL:\n    case TCP_KEEPCNT:\n#endif /* LWIP_TCP_KEEPALIVE */\n      break;\n\n    default:\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\\n\",\n                  s, optname));\n      err = ENOPROTOOPT;\n    }  /* switch (optname) */\n    break;\n#endif /* LWIP_TCP */\n#if LWIP_UDP && LWIP_UDPLITE\n/* Level: IPPROTO_UDPLITE */\n  case IPPROTO_UDPLITE:\n    if (optlen < sizeof(int)) {\n      err = EINVAL;\n      break;\n    }\n\n    /* If this is no UDP lite socket, ignore any options. */\n    if (sock->conn->type != NETCONN_UDPLITE)\n      return 0;\n\n    switch (optname) {\n    case UDPLITE_SEND_CSCOV:\n    case UDPLITE_RECV_CSCOV:\n      break;\n\n    default:\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\\n\",\n                  s, optname));\n      err = ENOPROTOOPT;\n    }  /* switch (optname) */\n    break;\n#endif /* LWIP_UDP && LWIP_UDPLITE */\n/* UNDEFINED LEVEL */\n  default:\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\\n\",\n                s, level, optname));\n    err = ENOPROTOOPT;\n  }  /* switch (level) */\n\n\n  if (err != ERR_OK) {\n    sock_set_errno(sock, err);\n    return -1;\n  }\n\n\n  /* Now do the actual option processing */\n  data.sock = sock;\n#ifdef LWIP_DEBUG\n  data.s = s;\n#endif /* LWIP_DEBUG */\n  data.level = level;\n  data.optname = optname;\n  data.optval = (void*)optval;\n  data.optlen = &optlen;\n  data.err = err;\n  tcpip_callback(lwip_setsockopt_internal, &data);\n  sys_arch_sem_wait(&sock->conn->op_completed, 0);\n  /* maybe lwip_setsockopt_internal has changed err */\n  err = data.err;\n\n  sock_set_errno(sock, err);\n  return err ? -1 : 0;\n}\n\nstatic void\nlwip_setsockopt_internal(void *arg)\n{\n  struct lwip_sock *sock;\n#ifdef LWIP_DEBUG\n  int s;\n#endif /* LWIP_DEBUG */\n  int level, optname;\n  const void *optval;\n  struct lwip_setgetsockopt_data *data;\n\n  LWIP_ASSERT(\"arg != NULL\", arg != NULL);\n\n  data = (struct lwip_setgetsockopt_data*)arg;\n  sock = data->sock;\n#ifdef LWIP_DEBUG\n  s = data->s;\n#endif /* LWIP_DEBUG */\n  level = data->level;\n  optname = data->optname;\n  optval = data->optval;\n\n  switch (level) {\n\n/* Level: SOL_SOCKET */\n  case SOL_SOCKET:\n    switch (optname) {\n\n    /* The option flags */\n    case SO_BROADCAST:\n    /* UNIMPL case SO_DEBUG: */\n    /* UNIMPL case SO_DONTROUTE: */\n    case SO_KEEPALIVE:\n    /* UNIMPL case SO_OOBINCLUDE: */\n#if SO_REUSE\n    case SO_REUSEADDR:\n    case SO_REUSEPORT:\n#endif /* SO_REUSE */\n    /* UNIMPL case SO_USELOOPBACK: */\n      if (*(int*)optval) {\n        sock->conn->pcb.ip->so_options |= optname;\n      } else {\n        sock->conn->pcb.ip->so_options &= ~optname;\n      }\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\\n\",\n                  s, optname, (*(int*)optval?\"on\":\"off\")));\n      break;\n#if LWIP_SO_RCVTIMEO\n    case SO_RCVTIMEO:\n      netconn_set_recvtimeout(sock->conn, *(int*)optval);\n      break;\n#endif /* LWIP_SO_RCVTIMEO */\n#if LWIP_SO_RCVBUF\n    case SO_RCVBUF:\n      netconn_set_recvbufsize(sock->conn, *(int*)optval);\n      break;\n#endif /* LWIP_SO_RCVBUF */\n#if LWIP_UDP\n    case SO_NO_CHECK:\n      if (*(int*)optval) {\n        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);\n      } else {\n        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);\n      }\n      break;\n#endif /* LWIP_UDP */\n    default:\n      LWIP_ASSERT(\"unhandled optname\", 0);\n      break;\n    }  /* switch (optname) */\n    break;\n\n/* Level: IPPROTO_IP */\n  case IPPROTO_IP:\n    switch (optname) {\n    case IP_TTL:\n      sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\\n\",\n                  s, sock->conn->pcb.ip->ttl));\n      break;\n    case IP_TOS:\n      sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\\n\",\n                  s, sock->conn->pcb.ip->tos));\n      break;\n#if LWIP_IGMP\n    case IP_MULTICAST_TTL:\n      sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);\n      break;\n    case IP_MULTICAST_IF:\n      inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);\n      break;\n    case IP_MULTICAST_LOOP:\n      if (*(u8_t*)optval) {\n        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);\n      } else {\n        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);\n      }\n      break;\n    case IP_ADD_MEMBERSHIP:\n    case IP_DROP_MEMBERSHIP:\n      {\n        /* If this is a TCP or a RAW socket, ignore these options. */\n        struct ip_mreq *imr = (struct ip_mreq *)optval;\n        ip_addr_t if_addr;\n        ip_addr_t multi_addr;\n        inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);\n        inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);\n        if(optname == IP_ADD_MEMBERSHIP){\n          data->err = igmp_joingroup(&if_addr, &multi_addr);\n        } else {\n          data->err = igmp_leavegroup(&if_addr, &multi_addr);\n        }\n        if(data->err != ERR_OK) {\n          data->err = EADDRNOTAVAIL;\n        }\n      }\n      break;\n#endif /* LWIP_IGMP */\n    default:\n      LWIP_ASSERT(\"unhandled optname\", 0);\n      break;\n    }  /* switch (optname) */\n    break;\n\n#if LWIP_TCP\n/* Level: IPPROTO_TCP */\n  case IPPROTO_TCP:\n    switch (optname) {\n    case TCP_NODELAY:\n      if (*(int*)optval) {\n        tcp_nagle_disable(sock->conn->pcb.tcp);\n      } else {\n        tcp_nagle_enable(sock->conn->pcb.tcp);\n      }\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\\n\",\n                  s, (*(int *)optval)?\"on\":\"off\") );\n      break;\n    case TCP_KEEPALIVE:\n      sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %\"U32_F\"\\n\",\n                  s, sock->conn->pcb.tcp->keep_idle));\n      break;\n\n#if LWIP_TCP_KEEPALIVE\n    case TCP_KEEPIDLE:\n      sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %\"U32_F\"\\n\",\n                  s, sock->conn->pcb.tcp->keep_idle));\n      break;\n    case TCP_KEEPINTVL:\n      sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %\"U32_F\"\\n\",\n                  s, sock->conn->pcb.tcp->keep_intvl));\n      break;\n    case TCP_KEEPCNT:\n      sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %\"U32_F\"\\n\",\n                  s, sock->conn->pcb.tcp->keep_cnt));\n      break;\n#endif /* LWIP_TCP_KEEPALIVE */\n    default:\n      LWIP_ASSERT(\"unhandled optname\", 0);\n      break;\n    }  /* switch (optname) */\n    break;\n#endif /* LWIP_TCP*/\n#if LWIP_UDP && LWIP_UDPLITE\n  /* Level: IPPROTO_UDPLITE */\n  case IPPROTO_UDPLITE:\n    switch (optname) {\n    case UDPLITE_SEND_CSCOV:\n      if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {\n        /* don't allow illegal values! */\n        sock->conn->pcb.udp->chksum_len_tx = 8;\n      } else {\n        sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;\n      }\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\\n\",\n                  s, (*(int*)optval)) );\n      break;\n    case UDPLITE_RECV_CSCOV:\n      if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {\n        /* don't allow illegal values! */\n        sock->conn->pcb.udp->chksum_len_rx = 8;\n      } else {\n        sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;\n      }\n      LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\\n\",\n                  s, (*(int*)optval)) );\n      break;\n    default:\n      LWIP_ASSERT(\"unhandled optname\", 0);\n      break;\n    }  /* switch (optname) */\n    break;\n#endif /* LWIP_UDP */\n  default:\n    LWIP_ASSERT(\"unhandled level\", 0);\n    break;\n  }  /* switch (level) */\n  sys_sem_signal(&sock->conn->op_completed);\n}\n\nint\nlwip_ioctl(int s, long cmd, void *argp)\n{\n  struct lwip_sock *sock = get_socket(s);\n  u8_t val;\n#if LWIP_SO_RCVBUF\n  u16_t buflen = 0;\n  s16_t recv_avail;\n#endif /* LWIP_SO_RCVBUF */\n\n  if (!sock) {\n    return -1;\n  }\n\n  switch (cmd) {\n#if LWIP_SO_RCVBUF\n  case FIONREAD:\n    if (!argp) {\n      sock_set_errno(sock, EINVAL);\n      return -1;\n    }\n\n    SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);\n    if (recv_avail < 0) {\n      recv_avail = 0;\n    }\n    *((u16_t*)argp) = (u16_t)recv_avail;\n\n    /* Check if there is data left from the last recv operation. /maq 041215 */\n    if (sock->lastdata) {\n      struct pbuf *p = (struct pbuf *)sock->lastdata;\n      if (netconn_type(sock->conn) != NETCONN_TCP) {\n        p = ((struct netbuf *)p)->p;\n      }\n      buflen = p->tot_len;\n      buflen -= sock->lastoffset;\n\n      *((u16_t*)argp) += buflen;\n    }\n\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_ioctl(%d, FIONREAD, %p) = %\"U16_F\"\\n\", s, argp, *((u16_t*)argp)));\n    sock_set_errno(sock, 0);\n    return 0;\n#endif /* LWIP_SO_RCVBUF */\n\n  case FIONBIO:\n    val = 0;\n    if (argp && *(u32_t*)argp) {\n      val = 1;\n    }\n    netconn_set_nonblocking(sock->conn, val);\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_ioctl(%d, FIONBIO, %d)\\n\", s, val));\n    sock_set_errno(sock, 0);\n    return 0;\n\n  default:\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\\n\", s, cmd, argp));\n    sock_set_errno(sock, ENOSYS); /* not yet implemented */\n    return -1;\n  } /* switch (cmd) */\n}\n\n/** A minimal implementation of fcntl.\n * Currently only the commands F_GETFL and F_SETFL are implemented.\n * Only the flag O_NONBLOCK is implemented.\n */\nint\nlwip_fcntl(int s, int cmd, int val)\n{\n  struct lwip_sock *sock = get_socket(s);\n  int ret = -1;\n\n  if (!sock || !sock->conn) {\n    return -1;\n  }\n\n  switch (cmd) {\n  case F_GETFL:\n    ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;\n    break;\n  case F_SETFL:\n    if ((val & ~O_NONBLOCK) == 0) {\n      /* only O_NONBLOCK, all other bits are zero */\n      netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);\n      ret = 0;\n    }\n    break;\n  default:\n    LWIP_DEBUGF(SOCKETS_DEBUG, (\"lwip_fcntl(%d, UNIMPL: %d, %d)\\n\", s, cmd, val));\n    break;\n  }\n  return ret;\n}\n\n#endif /* LWIP_SOCKET */\n"
  },
  {
    "path": "app/lwip/api/tcpip.c",
    "content": "/**\n * @file\n * Sequential API Main thread module\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if !NO_SYS /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/sys.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/tcpip.h\"\n#include \"lwip/init.h\"\n#include \"netif/etharp.h\"\n#include \"netif/ppp_oe.h\"\n\n/* global variables */\nstatic tcpip_init_done_fn tcpip_init_done;\nstatic void *tcpip_init_done_arg;\nstatic sys_mbox_t mbox;\n\n#if LWIP_TCPIP_CORE_LOCKING\n/** The global semaphore to lock the stack. */\nsys_mutex_t lock_tcpip_core;\n#endif /* LWIP_TCPIP_CORE_LOCKING */\n\n\n/**\n * The main lwIP thread. This thread has exclusive access to lwIP core functions\n * (unless access to them is not locked). Other threads communicate with this\n * thread using message boxes.\n *\n * It also starts all the timers to make sure they are running in the right\n * thread context.\n *\n * @param arg unused argument\n */\nstatic void\ntcpip_thread(void *arg)\n{\n  struct tcpip_msg *msg;\n  LWIP_UNUSED_ARG(arg);\n\n  if (tcpip_init_done != NULL) {//ûעԶʼ\n    tcpip_init_done(tcpip_init_done_arg);\n  }\n\n  LOCK_TCPIP_CORE();\n  while (1) {                          /* MAIN Loop */\n    UNLOCK_TCPIP_CORE();\n    LWIP_TCPIP_THREAD_ALIVE();\n    /* wait for a message, timeouts are processed while waiting */\n    sys_timeouts_mbox_fetch(&mbox, (void **)&msg);\n    LOCK_TCPIP_CORE();\n    switch (msg->type) {\n#if LWIP_NETCONN\n    case TCPIP_MSG_API://API\n      LWIP_DEBUGF(TCPIP_DEBUG, (\"tcpip_thread: API message %p\\n\", (void *)msg));\n      msg->msg.apimsg->function(&(msg->msg.apimsg->msg));\n      break;\n#endif /* LWIP_NETCONN */\n\n#if !LWIP_TCPIP_CORE_LOCKING_INPUT\n    case TCPIP_MSG_INPKT://ײݰ\n      LWIP_DEBUGF(TCPIP_DEBUG, (\"tcpip_thread: PACKET %p\\n\", (void *)msg));\n#if LWIP_ETHERNET\n      if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {//֧ARP\n        ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);//ARP\n      } else\n#endif /* LWIP_ETHERNET */\n      {\n        ip_input(msg->msg.inp.p, msg->msg.inp.netif);//IP\n      }\n      memp_free(MEMP_TCPIP_MSG_INPKT, msg);\n      break;\n#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */\n\n#if LWIP_NETIF_API\n    case TCPIP_MSG_NETIFAPI:\n      LWIP_DEBUGF(TCPIP_DEBUG, (\"tcpip_thread: Netif API message %p\\n\", (void *)msg));\n      msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));\n      break;\n#endif /* LWIP_NETIF_API */\n\n    case TCPIP_MSG_CALLBACK://ϲصʽִһ\n      LWIP_DEBUGF(TCPIP_DEBUG, (\"tcpip_thread: CALLBACK %p\\n\", (void *)msg));\n      msg->msg.cb.function(msg->msg.cb.ctx);\n      memp_free(MEMP_TCPIP_MSG_API, msg);\n      break;\n\n#if LWIP_TCPIP_TIMEOUT\n    case TCPIP_MSG_TIMEOUT://ϲעһʱ¼\n      LWIP_DEBUGF(TCPIP_DEBUG, (\"tcpip_thread: TIMEOUT %p\\n\", (void *)msg));\n      sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);\n      memp_free(MEMP_TCPIP_MSG_API, msg);\n      break;\n    case TCPIP_MSG_UNTIMEOUT://ϲɾһʱ¼\n      LWIP_DEBUGF(TCPIP_DEBUG, (\"tcpip_thread: UNTIMEOUT %p\\n\", (void *)msg));\n      sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);\n      memp_free(MEMP_TCPIP_MSG_API, msg);\n      break;\n#endif /* LWIP_TCPIP_TIMEOUT */\n\n    default:\n      LWIP_DEBUGF(TCPIP_DEBUG, (\"tcpip_thread: invalid message: %d\\n\", msg->type));\n      LWIP_ASSERT(\"tcpip_thread: invalid message\", 0);\n      break;\n    }\n  }\n}\n\n/**\n * Pass a received packet to tcpip_thread for input processing\n *\n * @param p the received packet, p->payload pointing to the Ethernet header or\n *          to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or\n *          NETIF_FLAG_ETHERNET flags)\n * @param inp the network interface on which the packet was received\n */\nerr_t\ntcpip_input(struct pbuf *p, struct netif *inp)\n{\n#if LWIP_TCPIP_CORE_LOCKING_INPUT\n  err_t ret;\n  LWIP_DEBUGF(TCPIP_DEBUG, (\"tcpip_input: PACKET %p/%p\\n\", (void *)p, (void *)inp));\n  LOCK_TCPIP_CORE();\n#if LWIP_ETHERNET\n  if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {\n    ret = ethernet_input(p, inp);\n  } else\n#endif /* LWIP_ETHERNET */\n  {\n    ret = ip_input(p, inp);\n  }\n  UNLOCK_TCPIP_CORE();\n  return ret;\n#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */\n  struct tcpip_msg *msg;\n\n  if (sys_mbox_valid(&mbox)) {\n    msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);\n    if (msg == NULL) {\n      return ERR_MEM;\n    }\n\n    msg->type = TCPIP_MSG_INPKT;\n    msg->msg.inp.p = p;\n    msg->msg.inp.netif = inp;\n    if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {\n      memp_free(MEMP_TCPIP_MSG_INPKT, msg);\n      return ERR_MEM;\n    }\n    return ERR_OK;\n  }\n  return ERR_VAL;\n#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */\n}\n\n/**\n * Call a specific function in the thread context of\n * tcpip_thread for easy access synchronization.\n * A function called in that way may access lwIP core code\n * without fearing concurrent access.\n *\n * @param f the function to call\n * @param ctx parameter passed to f\n * @param block 1 to block until the request is posted, 0 to non-blocking mode\n * @return ERR_OK if the function was called, another err_t if not\n */\nerr_t\ntcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block)\n{\n  struct tcpip_msg *msg;\n\n  if (sys_mbox_valid(&mbox)) {\n    msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);\n    if (msg == NULL) {\n      return ERR_MEM;\n    }\n\n    msg->type = TCPIP_MSG_CALLBACK;\n    msg->msg.cb.function = function;\n    msg->msg.cb.ctx = ctx;\n    if (block) {\n      sys_mbox_post(&mbox, msg);\n    } else {\n      if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {\n        memp_free(MEMP_TCPIP_MSG_API, msg);\n        return ERR_MEM;\n      }\n    }\n    return ERR_OK;\n  }\n  return ERR_VAL;\n}\n\n#if LWIP_TCPIP_TIMEOUT\n/**\n * call sys_timeout in tcpip_thread\n *\n * @param msec time in milliseconds for timeout\n * @param h function to be called on timeout\n * @param arg argument to pass to timeout function h\n * @return ERR_MEM on memory error, ERR_OK otherwise\n */\nerr_t\ntcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)\n{\n  struct tcpip_msg *msg;\n\n  if (sys_mbox_valid(&mbox)) {\n    msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);\n    if (msg == NULL) {\n      return ERR_MEM;\n    }\n\n    msg->type = TCPIP_MSG_TIMEOUT;\n    msg->msg.tmo.msecs = msecs;\n    msg->msg.tmo.h = h;\n    msg->msg.tmo.arg = arg;\n    sys_mbox_post(&mbox, msg);\n    return ERR_OK;\n  }\n  return ERR_VAL;\n}\n\n/**\n * call sys_untimeout in tcpip_thread\n *\n * @param msec time in milliseconds for timeout\n * @param h function to be called on timeout\n * @param arg argument to pass to timeout function h\n * @return ERR_MEM on memory error, ERR_OK otherwise\n */\nerr_t\ntcpip_untimeout(sys_timeout_handler h, void *arg)\n{\n  struct tcpip_msg *msg;\n\n  if (sys_mbox_valid(&mbox)) {\n    msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);\n    if (msg == NULL) {\n      return ERR_MEM;\n    }\n\n    msg->type = TCPIP_MSG_UNTIMEOUT;\n    msg->msg.tmo.h = h;\n    msg->msg.tmo.arg = arg;\n    sys_mbox_post(&mbox, msg);\n    return ERR_OK;\n  }\n  return ERR_VAL;\n}\n#endif /* LWIP_TCPIP_TIMEOUT */\n\n#if LWIP_NETCONN\n/**\n * Call the lower part of a netconn_* function\n * This function is then running in the thread context\n * of tcpip_thread and has exclusive access to lwIP core code.\n *\n * @param apimsg a struct containing the function to call and its parameters\n * @return ERR_OK if the function was called, another err_t if not\n */\nerr_t\ntcpip_apimsg(struct api_msg *apimsg)\n{\n  struct tcpip_msg msg;\n#ifdef LWIP_DEBUG\n  /* catch functions that don't set err */\n  apimsg->msg.err = ERR_VAL;\n#endif\n  \n  if (sys_mbox_valid(&mbox)) {//ںЧ\n    msg.type = TCPIP_MSG_API;\n    msg.msg.apimsg = apimsg;\n    sys_mbox_post(&mbox, &msg);//ͶϢ\n    sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0);//ȴϢ\n    return apimsg->msg.err;\n  }\n  return ERR_VAL;\n}\n\n#if LWIP_TCPIP_CORE_LOCKING\n/**\n * Call the lower part of a netconn_* function\n * This function has exclusive access to lwIP core code by locking it\n * before the function is called.\n *\n * @param apimsg a struct containing the function to call and its parameters\n * @return ERR_OK (only for compatibility fo tcpip_apimsg())\n */\nerr_t\ntcpip_apimsg_lock(struct api_msg *apimsg)\n{\n#ifdef LWIP_DEBUG\n  /* catch functions that don't set err */\n  apimsg->msg.err = ERR_VAL;\n#endif\n\n  LOCK_TCPIP_CORE();\n  apimsg->function(&(apimsg->msg));\n  UNLOCK_TCPIP_CORE();\n  return apimsg->msg.err;\n\n}\n#endif /* LWIP_TCPIP_CORE_LOCKING */\n#endif /* LWIP_NETCONN */\n\n#if LWIP_NETIF_API\n#if !LWIP_TCPIP_CORE_LOCKING\n/**\n * Much like tcpip_apimsg, but calls the lower part of a netifapi_*\n * function.\n *\n * @param netifapimsg a struct containing the function to call and its parameters\n * @return error code given back by the function that was called\n */\nerr_t\ntcpip_netifapi(struct netifapi_msg* netifapimsg)\n{\n  struct tcpip_msg msg;\n  \n  if (sys_mbox_valid(&mbox)) {\n    err_t err = sys_sem_new(&netifapimsg->msg.sem, 0);\n    if (err != ERR_OK) {\n      netifapimsg->msg.err = err;\n      return err;\n    }\n    \n    msg.type = TCPIP_MSG_NETIFAPI;\n    msg.msg.netifapimsg = netifapimsg;\n    sys_mbox_post(&mbox, &msg);\n    sys_sem_wait(&netifapimsg->msg.sem);\n    sys_sem_free(&netifapimsg->msg.sem);\n    return netifapimsg->msg.err;\n  }\n  return ERR_VAL;\n}\n#else /* !LWIP_TCPIP_CORE_LOCKING */\n/**\n * Call the lower part of a netifapi_* function\n * This function has exclusive access to lwIP core code by locking it\n * before the function is called.\n *\n * @param netifapimsg a struct containing the function to call and its parameters\n * @return ERR_OK (only for compatibility fo tcpip_netifapi())\n */\nerr_t\ntcpip_netifapi_lock(struct netifapi_msg* netifapimsg)\n{\n  LOCK_TCPIP_CORE();  \n  netifapimsg->function(&(netifapimsg->msg));\n  UNLOCK_TCPIP_CORE();\n  return netifapimsg->msg.err;\n}\n#endif /* !LWIP_TCPIP_CORE_LOCKING */\n#endif /* LWIP_NETIF_API */\n\n/**\n * Initialize this module:\n * - initialize all sub modules\n * - start the tcpip_thread\n *\n * @param initfunc a function to call when tcpip_thread is running and finished initializing\n * @param arg argument to pass to initfunc\n */\nvoid\ntcpip_init(tcpip_init_done_fn initfunc, void *arg)\n{\n  lwip_init();//ʼں\n\n  tcpip_init_done = initfunc;//עûԶ庯\n  tcpip_init_done_arg = arg;//\n  if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) {//ں\n    LWIP_ASSERT(\"failed to create tcpip_thread mbox\", 0);\n  }\n#if LWIP_TCPIP_CORE_LOCKING\n  if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) {\n    LWIP_ASSERT(\"failed to create lock_tcpip_core\", 0);\n  }\n#endif /* LWIP_TCPIP_CORE_LOCKING */\n\n  sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);//ں˽\n}\n\n/**\n * Simple callback function used with tcpip_callback to free a pbuf\n * (pbuf_free has a wrong signature for tcpip_callback)\n *\n * @param p The pbuf (chain) to be dereferenced.\n */\nstatic void\npbuf_free_int(void *p)\n{\n  struct pbuf *q = (struct pbuf *)p;\n  pbuf_free(q);\n}\n\n/**\n * A simple wrapper function that allows you to free a pbuf from interrupt context.\n *\n * @param p The pbuf (chain) to be dereferenced.\n * @return ERR_OK if callback could be enqueued, an err_t if not\n */\nerr_t\npbuf_free_callback(struct pbuf *p)\n{\n  return tcpip_callback_with_block(pbuf_free_int, p, 0);\n}\n\n/**\n * A simple wrapper function that allows you to free heap memory from\n * interrupt context.\n *\n * @param m the heap memory to free\n * @return ERR_OK if callback could be enqueued, an err_t if not\n */\nerr_t\nmem_free_callback(void *m)\n{\n  return tcpip_callback_with_block(mem_free, m, 0);\n}\n\n#endif /* !NO_SYS */\n"
  },
  {
    "path": "app/lwip/app/Makefile",
    "content": "\r\n#############################################################\r\n# Required variables for each makefile\r\n# Discard this section from all parent makefiles\r\n# Expected variables (with automatic defaults):\r\n#   CSRCS (all \"C\" files in the dir)\r\n#   SUBDIRS (all subdirs with a Makefile)\r\n#   GEN_LIBS - list of libs to be generated ()\r\n#   GEN_IMAGES - list of images to be generated ()\r\n#   COMPONENTS_xxx - a list of libs/objs in the form\r\n#     subdir/lib to be extracted and rolled up into\r\n#     a generated lib/image xxx.a ()\r\n#\r\nifndef PDIR\r\n\r\nGEN_LIBS = liblwipapp.a\r\n\r\nendif\r\n\r\n\r\n#############################################################\r\n# Configuration i.e. compile options etc.\r\n# Target specific stuff (defines etc.) goes in here!\r\n# Generally values applying to a tree are captured in the\r\n#   makefile at its root level - these are then overridden\r\n#   for a subtree within the makefile rooted therein\r\n#\r\n#DEFINES += \r\n\r\n#############################################################\r\n# Recursion Magic - Don't touch this!!\r\n#\r\n# Each subtree potentially has an include directory\r\n#   corresponding to the common APIs applicable to modules\r\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\r\n#   of a module can only contain the include directories up\r\n#   its parent path, and not its siblings\r\n#\r\n# Required for each makefile to inherit from the parent\r\n#\r\n\r\nINCLUDES := $(INCLUDES) -I $(PDIR)include\r\nINCLUDES += -I ./\r\nPDIR := ../$(PDIR)\r\nsinclude $(PDIR)Makefile\r\n\r\n"
  },
  {
    "path": "app/lwip/app/dhcpserver.c",
    "content": "#include \"lwip/inet.h\"\r\n#include \"lwip/err.h\"\n#include \"lwip/pbuf.h\"\r\n#include \"lwip/udp.h\"\r\n#include \"lwip/mem.h\"\r\n//#include \"crypto/common.h\"\r\n#include \"osapi.h\"\r\n#include \"lwip/app/dhcpserver.h\"\r\n\r\n#ifndef LWIP_OPEN_SRC\r\n#include \"net80211/ieee80211_var.h\"\r\n#endif\r\n\r\n#include \"user_interface.h\"\r\n\r\n#ifdef MEMLEAK_DEBUG\r\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\r\n#endif\r\n\r\n////////////////////////////////////////////////////////////////////////////////////\r\n//static const uint8_t xid[4] = {0xad, 0xde, 0x12, 0x23};\r\n//static u8_t old_xid[4] = {0};\r\nstatic const uint32 magic_cookie ICACHE_RODATA_ATTR = 0x63538263;\r\nstatic struct udp_pcb *pcb_dhcps = NULL;\r\nstatic struct ip_addr broadcast_dhcps;\r\nstatic struct ip_addr server_address;\r\nstatic struct ip_addr client_address;//added\r\nstatic struct ip_addr client_address_plus;\r\n\r\nstatic struct dhcps_lease dhcps_lease;\r\n//static bool dhcps_lease_flag = true;\r\nstatic list_node *plist = NULL;\r\nstatic uint8 offer = 0xFF;\r\nstatic bool renew = false;\r\n#define DHCPS_LEASE_TIME_DEF\t(120)\r\nuint32 dhcps_lease_time = DHCPS_LEASE_TIME_DEF;  //minute\r\n/******************************************************************************\r\n * FunctionName : node_insert_to_list\r\n * Description  : insert the node to the list\r\n * Parameters   : arg -- Additional argument to pass to the callback function\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid ICACHE_FLASH_ATTR node_insert_to_list(list_node **phead, list_node* pinsert)\r\n{\r\n\tlist_node *plist = NULL;\r\n\tstruct dhcps_pool *pdhcps_pool = NULL;\r\n\tstruct dhcps_pool *pdhcps_node = NULL;\r\n\tif (*phead == NULL)\r\n\t\t*phead = pinsert;\r\n\telse {\r\n\t\tplist = *phead;\r\n\t\tpdhcps_node = pinsert->pnode;\r\n\t\tpdhcps_pool = plist->pnode;\r\n\r\n\t\tif(pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {\r\n\t\t    pinsert->pnext = plist;\r\n\t\t    *phead = pinsert;\r\n\t\t} else {\r\n            while (plist->pnext != NULL) {\r\n                pdhcps_pool = plist->pnext->pnode;\r\n                if (pdhcps_node->ip.addr < pdhcps_pool->ip.addr) {\r\n                    pinsert->pnext = plist->pnext;\r\n                    plist->pnext = pinsert;\r\n                    break;\r\n                }\r\n                plist = plist->pnext;\r\n            }\r\n\r\n            if(plist->pnext == NULL) {\r\n                plist->pnext = pinsert;\r\n            }\r\n\t\t}\r\n\t}\r\n//\tpinsert->pnext = NULL;\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : node_delete_from_list\r\n * Description  : remove the node from list\r\n * Parameters   : arg -- Additional argument to pass to the callback function\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid ICACHE_FLASH_ATTR node_remove_from_list(list_node **phead, list_node* pdelete)\r\n{\r\n\tlist_node *plist = NULL;\r\n\r\n\tplist = *phead;\r\n\tif (plist == NULL){\r\n\t\t*phead = NULL;\r\n\t} else {\r\n\t\tif (plist == pdelete){\r\n\t\t\t*phead = plist->pnext;\r\n\t\t} else {\r\n\t\t\twhile (plist != NULL) {\r\n\t\t\t\tif (plist->pnext == pdelete){\r\n\t\t\t\t\tplist->pnext = pdelete->pnext;\r\n\t\t\t\t}\r\n\t\t\t\tplist = plist->pnext;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n/*\r\n * ��DHCP msg��Ϣ�ṹ����������\r\n *\r\n * @param optptr -- DHCP msg��Ϣλ��\r\n * @param type -- Ҫ��ӵ�����option\r\n *\r\n * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ\r\n */\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic uint8_t* ICACHE_FLASH_ATTR add_msg_type(uint8_t *optptr, uint8_t type)\r\n{\r\n\r\n        *optptr++ = DHCP_OPTION_MSG_TYPE;\r\n        *optptr++ = 1;\r\n        *optptr++ = type;\r\n        return optptr;\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n/*\r\n * ��DHCP msg�ṹ������offerӦ������\r\n *\r\n * @param optptr -- DHCP msg��Ϣλ��\r\n *\r\n * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ\r\n */\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic uint8_t* ICACHE_FLASH_ATTR add_offer_options(uint8_t *optptr)\r\n{\r\n        struct ip_addr ipadd;\r\n\r\n        ipadd.addr = *( (uint32_t *) &server_address);\r\n\r\n#ifdef USE_CLASS_B_NET\r\n        *optptr++ = DHCP_OPTION_SUBNET_MASK;\r\n        *optptr++ = 4;  //length\r\n        *optptr++ = 255;\r\n        *optptr++ = 240;\t\r\n        *optptr++ = 0;\r\n        *optptr++ = 0;\r\n#else\r\n        *optptr++ = DHCP_OPTION_SUBNET_MASK;\r\n        *optptr++ = 4;  \r\n        *optptr++ = 255;\r\n        *optptr++ = 255;\t\r\n        *optptr++ = 255;\r\n        *optptr++ = 0;\r\n#endif\r\n\r\n        *optptr++ = DHCP_OPTION_LEASE_TIME;\r\n        *optptr++ = 4;  \r\n        *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 24) & 0xFF;\r\n        *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 16) & 0xFF;\r\n        *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 8) & 0xFF;\r\n        *optptr++ = ((DHCPS_LEASE_TIMER * 60) >> 0) & 0xFF;\r\n\r\n        *optptr++ = DHCP_OPTION_SERVER_ID;\r\n        *optptr++ = 4;  \r\n        *optptr++ = ip4_addr1( &ipadd);\r\n        *optptr++ = ip4_addr2( &ipadd);\r\n        *optptr++ = ip4_addr3( &ipadd);\r\n        *optptr++ = ip4_addr4( &ipadd);\r\n\r\n        if (dhcps_router_enabled(offer)){\r\n        \tstruct ip_info if_ip;\r\n\t\t\tos_bzero(&if_ip, sizeof(struct ip_info));\r\n\t\t\twifi_get_ip_info(SOFTAP_IF, &if_ip);\r\n\r\n\t\t\t*optptr++ = DHCP_OPTION_ROUTER;\r\n\t\t\t*optptr++ = 4;\r\n\t\t\t*optptr++ = ip4_addr1( &if_ip.gw);\r\n\t\t\t*optptr++ = ip4_addr2( &if_ip.gw);\r\n\t\t\t*optptr++ = ip4_addr3( &if_ip.gw);\r\n\t\t\t*optptr++ = ip4_addr4( &if_ip.gw);\r\n        }\r\n\r\n#ifdef USE_DNS\r\n\t    *optptr++ = DHCP_OPTION_DNS_SERVER;\r\n\t    *optptr++ = 4;\r\n\t    *optptr++ = ip4_addr1( &ipadd);\r\n\t\t*optptr++ = ip4_addr2( &ipadd);\r\n\t\t*optptr++ = ip4_addr3( &ipadd);\r\n\t\t*optptr++ = ip4_addr4( &ipadd);\r\n#endif\r\n\r\n#ifdef CLASS_B_NET\r\n        *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;\r\n        *optptr++ = 4;  \r\n        *optptr++ = ip4_addr1( &ipadd);\r\n        *optptr++ = 255;\r\n        *optptr++ = 255;\r\n        *optptr++ = 255;\r\n#else\r\n        *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;\r\n        *optptr++ = 4;  \r\n        *optptr++ = ip4_addr1( &ipadd);\r\n        *optptr++ = ip4_addr2( &ipadd);\r\n        *optptr++ = ip4_addr3( &ipadd);\r\n        *optptr++ = 255;\r\n#endif\r\n\r\n        *optptr++ = DHCP_OPTION_INTERFACE_MTU;\r\n        *optptr++ = 2;  \r\n#ifdef CLASS_B_NET\r\n        *optptr++ = 0x05;\t\r\n        *optptr++ = 0xdc;\r\n#else\r\n        *optptr++ = 0x02;\t\r\n        *optptr++ = 0x40;\r\n#endif\r\n\r\n        *optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY;\r\n        *optptr++ = 1;  \r\n        *optptr++ = 0x00; \r\n\r\n        *optptr++ = 43;\t\r\n        *optptr++ = 6;\t\r\n\r\n        *optptr++ = 0x01;\t\r\n        *optptr++ = 4;  \r\n        *optptr++ = 0x00;\r\n        *optptr++ = 0x00;\r\n        *optptr++ = 0x00;\r\n        *optptr++ = 0x02; \t\r\n\r\n        return optptr;\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n/*\r\n * ��DHCP msg�ṹ����ӽ����־����\r\n *\r\n * @param optptr -- DHCP msg��Ϣλ��\r\n *\r\n * @return uint8_t* ����DHCP msgƫ�Ƶ�ַ\r\n */\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic uint8_t* ICACHE_FLASH_ATTR add_end(uint8_t *optptr)\r\n{\r\n\r\n        *optptr++ = DHCP_OPTION_END;\r\n        return optptr;\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic void ICACHE_FLASH_ATTR create_msg(struct dhcps_msg *m)\r\n{\r\n        struct ip_addr client;\r\n\r\n        client.addr = *( (uint32_t *) &client_address);\r\n\r\n        m->op = DHCP_REPLY;\r\n        m->htype = DHCP_HTYPE_ETHERNET;\r\n        m->hlen = 6;  \r\n        m->hops = 0;\r\n//        os_memcpy((char *) xid, (char *) m->xid, sizeof(m->xid));\r\n        m->secs = 0;\r\n        m->flags = htons(BOOTP_BROADCAST); \r\n\r\n        os_memcpy((char *) m->yiaddr, (char *) &client.addr, sizeof(m->yiaddr));\r\n\r\n        os_memset((char *) m->ciaddr, 0, sizeof(m->ciaddr));\r\n        os_memset((char *) m->siaddr, 0, sizeof(m->siaddr));\r\n        os_memset((char *) m->giaddr, 0, sizeof(m->giaddr));\r\n        os_memset((char *) m->sname, 0, sizeof(m->sname));\r\n        os_memset((char *) m->file, 0, sizeof(m->file));\r\n\r\n        os_memset((char *) m->options, 0, sizeof(m->options));\r\n        os_memcpy((char *) m->options, &magic_cookie, sizeof(magic_cookie));\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n/*\r\n * ����һ��OFFER\r\n *\r\n * @param -- m ָ����Ҫ���͵�DHCP msg����\r\n */\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic void ICACHE_FLASH_ATTR send_offer(struct dhcps_msg *m)\r\n{\r\n        uint8_t *end;\r\n\t    struct pbuf *p, *q;\r\n\t    u8_t *data;\r\n\t    u16_t cnt=0;\r\n\t    u16_t i;\r\n\t\terr_t SendOffer_err_t;\r\n        create_msg(m);\r\n\r\n        end = add_msg_type(&m->options[4], DHCPOFFER);\r\n        end = add_offer_options(end);\r\n        end = add_end(end);\r\n\r\n\t    p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);\r\n#if DHCPS_DEBUG\r\n\t\tos_printf(\"udhcp: send_offer>>p->ref = %d\\n\", p->ref);\r\n#endif\r\n\t    if(p != NULL){\r\n\t       \r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_offer>>pbuf_alloc succeed\\n\");\r\n\t        os_printf(\"dhcps: send_offer>>p->tot_len = %d\\n\", p->tot_len);\r\n\t        os_printf(\"dhcps: send_offer>>p->len = %d\\n\", p->len);\r\n#endif\r\n\t        q = p;\r\n\t        while(q != NULL){\r\n\t            data = (u8_t *)q->payload;\r\n\t            for(i=0; i<q->len; i++)\r\n\t            {\r\n\t                data[i] = ((u8_t *) m)[cnt++];\r\n#if DHCPS_DEBUG\r\n\t\t\t\t\tos_printf(\"%02x \",data[i]);\r\n\t\t\t\t\tif((i+1)%16 == 0){\r\n\t\t\t\t\t\tos_printf(\"\\n\");\r\n\t\t\t\t\t}\r\n#endif\r\n\t            }\r\n\r\n\t            q = q->next;\r\n\t        }\r\n\t    }else{\r\n\t        \r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_offer>>pbuf_alloc failed\\n\");\r\n#endif\r\n\t        return;\r\n\t    }\r\n        SendOffer_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT );\r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_offer>>udp_sendto result %x\\n\",SendOffer_err_t);\r\n#endif\r\n\t    if(p->ref != 0){\t\r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"udhcp: send_offer>>free pbuf\\n\");\r\n#endif\r\n\t        pbuf_free(p);\r\n\t    }\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n/*\r\n * ����һ��NAK��Ϣ\r\n *\r\n * @param m ָ����Ҫ���͵�DHCP msg����\r\n */\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic void ICACHE_FLASH_ATTR send_nak(struct dhcps_msg *m)\r\n{\r\n\r\n    \tu8_t *end;\r\n\t    struct pbuf *p, *q;\r\n\t    u8_t *data;\r\n\t    u16_t cnt=0;\r\n\t    u16_t i;\r\n\t\terr_t SendNak_err_t;\r\n        create_msg(m);\r\n\r\n        end = add_msg_type(&m->options[4], DHCPNAK);\r\n        end = add_end(end);\r\n\r\n\t    p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);\r\n#if DHCPS_DEBUG\r\n\t\tos_printf(\"udhcp: send_nak>>p->ref = %d\\n\", p->ref);\r\n#endif\r\n\t    if(p != NULL){\r\n\t        \r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_nak>>pbuf_alloc succeed\\n\");\r\n\t        os_printf(\"dhcps: send_nak>>p->tot_len = %d\\n\", p->tot_len);\r\n\t        os_printf(\"dhcps: send_nak>>p->len = %d\\n\", p->len);\r\n#endif\r\n\t        q = p;\r\n\t        while(q != NULL){\r\n\t            data = (u8_t *)q->payload;\r\n\t            for(i=0; i<q->len; i++)\r\n\t            {\r\n\t                data[i] = ((u8_t *) m)[cnt++];\r\n#if DHCPS_DEBUG\t\t\t\t\t\r\n\t\t\t\t\tos_printf(\"%02x \",data[i]);\r\n\t\t\t\t\tif((i+1)%16 == 0){\r\n\t\t\t\t\t\tos_printf(\"\\n\");\r\n\t\t\t\t\t}\r\n#endif\r\n\t            }\r\n\r\n\t            q = q->next;\r\n\t        }\r\n\t    }else{\r\n\t        \r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_nak>>pbuf_alloc failed\\n\");\r\n#endif\r\n\t        return;\r\n    \t}\r\n        SendNak_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT );\r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_nak>>udp_sendto result %x\\n\",SendNak_err_t);\r\n#endif\r\n \t    if(p->ref != 0){\r\n#if DHCPS_DEBUG\t\t\t\r\n\t        os_printf(\"udhcp: send_nak>>free pbuf\\n\");\r\n#endif\r\n\t        pbuf_free(p);\r\n\t    }\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n/*\r\n * ����һ��ACK��DHCP�ͻ���\r\n *\r\n * @param m ָ����Ҫ���͵�DHCP msg����\r\n */\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic void ICACHE_FLASH_ATTR send_ack(struct dhcps_msg *m)\r\n{\r\n\r\n\t\tu8_t *end;\r\n\t    struct pbuf *p, *q;\r\n\t    u8_t *data;\r\n\t    u16_t cnt=0;\r\n\t    u16_t i;\r\n\t\terr_t SendAck_err_t;\r\n        create_msg(m);\r\n\r\n        end = add_msg_type(&m->options[4], DHCPACK);\r\n        end = add_offer_options(end);\r\n        end = add_end(end);\r\n\t    \r\n\t    p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);\r\n#if DHCPS_DEBUG\r\n\t\tos_printf(\"udhcp: send_ack>>p->ref = %d\\n\", p->ref);\r\n#endif\r\n\t    if(p != NULL){\r\n\t        \r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_ack>>pbuf_alloc succeed\\n\");\r\n\t        os_printf(\"dhcps: send_ack>>p->tot_len = %d\\n\", p->tot_len);\r\n\t        os_printf(\"dhcps: send_ack>>p->len = %d\\n\", p->len);\r\n#endif\r\n\t        q = p;\r\n\t        while(q != NULL){\r\n\t            data = (u8_t *)q->payload;\r\n\t            for(i=0; i<q->len; i++)\r\n\t            {\r\n\t                data[i] = ((u8_t *) m)[cnt++];\r\n#if DHCPS_DEBUG\t\t\t\t\t\r\n\t\t\t\t\tos_printf(\"%02x \",data[i]);\r\n\t\t\t\t\tif((i+1)%16 == 0){\r\n\t\t\t\t\t\tos_printf(\"\\n\");\r\n\t\t\t\t\t}\r\n#endif\r\n\t            }\r\n\r\n\t            q = q->next;\r\n\t        }\r\n\t    }else{\r\n\t    \r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_ack>>pbuf_alloc failed\\n\");\r\n#endif\r\n\t        return;\r\n\t    }\r\n        SendAck_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT );\r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: send_ack>>udp_sendto result %x\\n\",SendAck_err_t);\r\n#endif\r\n\t    \r\n\t    if(p->ref != 0){\r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"udhcp: send_ack>>free pbuf\\n\");\r\n#endif\r\n\t        pbuf_free(p);\r\n\t    }\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n/*\r\n * ����DHCP�ͻ��˷�����DHCP����������Ϣ�����Բ�ͬ��DHCP��������������Ӧ��Ӧ��\r\n *\r\n * @param optptr DHCP msg�е���������\r\n * @param len ��������Ĵ��?(byte)\r\n *\r\n * @return uint8_t ���ش�����DHCP Server״ֵ̬\r\n */\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic uint8_t ICACHE_FLASH_ATTR parse_options(uint8_t *optptr, sint16_t len)\r\n{\r\n        struct ip_addr client;\r\n    \tbool is_dhcp_parse_end = false;\r\n    \tstruct dhcps_state s;\r\n\r\n        client.addr = *( (uint32_t *) &client_address);// Ҫ�����DHCP�ͻ��˵�IP\r\n\r\n        u8_t *end = optptr + len;\r\n        u16_t type = 0;\r\n\r\n        s.state = DHCPS_STATE_IDLE;\r\n\r\n        while (optptr < end) {\r\n#if DHCPS_DEBUG\r\n        \tos_printf(\"dhcps: (sint16_t)*optptr = %d\\n\", (sint16_t)*optptr);\r\n#endif\r\n        \tswitch ((sint16_t) *optptr) {\r\n\r\n                case DHCP_OPTION_MSG_TYPE:\t//53\r\n                        type = *(optptr + 2);\r\n                        break;\r\n\r\n                case DHCP_OPTION_REQ_IPADDR://50\r\n                        if( os_memcmp( (char *) &client.addr, (char *) optptr+2,4)==0 ) {\r\n#if DHCPS_DEBUG\r\n                    \t\tos_printf(\"dhcps: DHCP_OPTION_REQ_IPADDR = 0 ok\\n\");\r\n#endif\r\n                            s.state = DHCPS_STATE_ACK;\r\n                        }else {\r\n#if DHCPS_DEBUG\r\n                    \t\tos_printf(\"dhcps: DHCP_OPTION_REQ_IPADDR != 0 err\\n\");\r\n#endif\r\n                            s.state = DHCPS_STATE_NAK;\r\n                        }\r\n                        break;\r\n                case DHCP_OPTION_END:\r\n\t\t\t            {\r\n\t\t\t                is_dhcp_parse_end = true;\r\n\t\t\t            }\r\n                        break;\r\n            }\r\n\r\n\t\t    if(is_dhcp_parse_end){\r\n\t\t            break;\r\n\t\t    }\r\n\r\n            optptr += optptr[1] + 2;\r\n        }\r\n\r\n        switch (type){\r\n        \r\n        \tcase DHCPDISCOVER://1\r\n                s.state = DHCPS_STATE_OFFER;\r\n#if DHCPS_DEBUG\r\n            \tos_printf(\"dhcps: DHCPD_STATE_OFFER\\n\");\r\n#endif\r\n                break;\r\n\r\n        \tcase DHCPREQUEST://3\r\n                if ( !(s.state == DHCPS_STATE_ACK || s.state == DHCPS_STATE_NAK) ) {\r\n                    if(renew == true) {\r\n                        s.state = DHCPS_STATE_ACK;\r\n                    } else {\r\n                        s.state = DHCPS_STATE_NAK;\r\n                    }\r\n#if DHCPS_DEBUG\r\n                \t\tos_printf(\"dhcps: DHCPD_STATE_NAK\\n\");\r\n#endif\r\n                }\r\n                break;\r\n\r\n\t\t\tcase DHCPDECLINE://4\r\n                s.state = DHCPS_STATE_IDLE;\r\n#if DHCPS_DEBUG\r\n            \tos_printf(\"dhcps: DHCPD_STATE_IDLE\\n\");\r\n#endif\r\n                break;\r\n\r\n        \tcase DHCPRELEASE://7\r\n                s.state = DHCPS_STATE_RELEASE;\r\n#if DHCPS_DEBUG\r\n            \tos_printf(\"dhcps: DHCPD_STATE_IDLE\\n\");\r\n#endif\r\n                break;\r\n        }\r\n#if DHCPS_DEBUG\r\n    \tos_printf(\"dhcps: return s.state = %d\\n\", s.state);\r\n#endif\r\n        return s.state;\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic sint16_t ICACHE_FLASH_ATTR parse_msg(struct dhcps_msg *m, u16_t len)\r\n{\n\t\tif(os_memcmp((char *)m->options,\r\n              &magic_cookie,\r\n              sizeof(magic_cookie)) == 0){\r\n#if DHCPS_DEBUG\r\n        \tos_printf(\"dhcps: len = %d\\n\", len);\r\n#endif\r\n\t        /*\r\n         \t * ��¼��ǰ��xid���ﴦ���?\r\n         \t * �˺�ΪDHCP�ͻ����������û�ͳһ��ȡIPʱ��\r\n         \t*/\r\n//\t        if((old_xid[0] == 0) &&\r\n//\t           (old_xid[1] == 0) &&\r\n//\t           (old_xid[2] == 0) &&\r\n//\t           (old_xid[3] == 0)){\r\n//\t            /*\r\n//\t             * old_xidδ��¼�κ����?\r\n//\t             * �϶��ǵ�һ��ʹ��\r\n//\t            */\r\n//\t            os_memcpy((char *)old_xid, (char *)m->xid, sizeof(m->xid));\r\n//\t        }else{\r\n//\t            /*\r\n//\t             * ���δ����DHCP msg��Я���xid���ϴμ�¼�Ĳ�ͬ��\r\n//\t             * �϶�Ϊ��ͬ��DHCP�ͻ��˷��ͣ���ʱ����Ҫ����Ŀͻ���IP\r\n//\t             * ���� 192.168.4.100(0x6404A8C0) <--> 192.168.4.200(0xC804A8C0)\r\n//\t             *\r\n//\t            */\r\n//\t            if(os_memcmp((char *)old_xid, (char *)m->xid, sizeof(m->xid)) != 0){\r\n\t                /*\r\n                 \t * ��¼���ε�xid�ţ�ͬʱ�����IP����\r\n                 \t*/\r\n\t                struct ip_addr addr_tmp;    \r\n//\t                os_memcpy((char *)old_xid, (char *)m->xid, sizeof(m->xid));\r\n\r\n//\t                {\r\n\t\t\t\t\t\tstruct dhcps_pool *pdhcps_pool = NULL;\r\n\t\t\t\t\t\tlist_node *pnode = NULL;\r\n\t\t\t\t\t\tlist_node *pback_node = NULL;\r\n\t\t\t\t\t\tstruct ip_addr first_address;\r\n\t\t\t\t\t\tbool flag = false;\r\n\r\n//\t\t\t\t\t\tPOOL_START:\r\n\t\t\t\t\t\tfirst_address.addr = dhcps_lease.start_ip.addr;\r\n\t\t\t\t\t\tclient_address.addr = client_address_plus.addr;\r\n\t\t\t\t\t\trenew = false;\r\n//\t\t\t\t\t\t\taddr_tmp.addr =  htonl(client_address_plus.addr);\r\n//\t\t\t\t\t\t\taddr_tmp.addr++;\r\n//\t\t\t\t\t\t\tclient_address_plus.addr = htonl(addr_tmp.addr);\r\n\t\t\t\t\t\tfor (pback_node = plist; pback_node != NULL;pback_node = pback_node->pnext) {\r\n\t\t\t\t\t\t\tpdhcps_pool = pback_node->pnode;\r\n\t\t\t\t\t\t\tif (os_memcmp(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac)) == 0){\r\n//\t\t\t\t\t\t\t\t\tos_printf(\"the same device request ip\\n\");\r\n\t\t\t\t\t\t\t\tif (os_memcmp(&pdhcps_pool->ip.addr, m->ciaddr, sizeof(pdhcps_pool->ip.addr)) == 0) {\r\n\t\t\t\t\t\t\t\t    renew = true;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\tclient_address.addr = pdhcps_pool->ip.addr;\r\n\t\t\t\t\t\t\t\tpdhcps_pool->lease_timer = DHCPS_LEASE_TIMER;\r\n\t\t\t\t\t\t\t\tpnode = pback_node;\r\n\t\t\t\t\t\t\t\tgoto POOL_CHECK;\r\n\t\t\t\t\t\t\t} else if (pdhcps_pool->ip.addr == client_address_plus.addr){\r\n//\t\t\t\t\t\t\t\t\tclient_address.addr = client_address_plus.addr;\r\n//\t\t\t\t\t\t\t\t\tos_printf(\"the ip addr has been request\\n\");\r\n\t\t\t\t\t\t\t\taddr_tmp.addr = htonl(client_address_plus.addr);\r\n\t\t\t\t\t\t\t\taddr_tmp.addr++;\r\n\t\t\t\t\t\t\t\tclient_address_plus.addr = htonl(addr_tmp.addr);\r\n\t\t\t\t\t\t\t\tclient_address.addr = client_address_plus.addr;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif(flag == false) { // search the fisrt unused ip\r\n                                if(first_address.addr < pdhcps_pool->ip.addr) {\r\n                                    flag = true;\r\n                                } else {\r\n                                    addr_tmp.addr = htonl(first_address.addr);\r\n                                    addr_tmp.addr++;\r\n                                    first_address.addr = htonl(addr_tmp.addr);\r\n                                }\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (client_address_plus.addr > dhcps_lease.end_ip.addr) {\r\n\t\t\t\t\t\t    client_address.addr = first_address.addr;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (client_address.addr > dhcps_lease.end_ip.addr) {\r\n\t\t\t\t\t\t    client_address_plus.addr = dhcps_lease.start_ip.addr;\r\n\t\t\t\t\t\t    pdhcps_pool = NULL;\r\n\t\t\t\t\t\t    pnode = NULL;\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t    pdhcps_pool = (struct dhcps_pool *)os_zalloc(sizeof(struct dhcps_pool));\r\n\t\t\t\t\t\t    pdhcps_pool->ip.addr = client_address.addr;\r\n\t\t\t\t\t\t    os_memcpy(pdhcps_pool->mac, m->chaddr, sizeof(pdhcps_pool->mac));\r\n\t\t\t\t\t\t    pdhcps_pool->lease_timer = DHCPS_LEASE_TIMER;\r\n\t\t\t\t\t\t    pnode = (list_node *)os_zalloc(sizeof(list_node ));\r\n\t\t\t\t\t\t    pnode->pnode = pdhcps_pool;\r\n\t\t\t\t\t\t    pnode->pnext = NULL;\r\n\t\t\t\t\t\t    node_insert_to_list(&plist,pnode);\r\n\t\t\t\t\t\t    if (client_address.addr == dhcps_lease.end_ip.addr) {\r\n\t\t\t\t\t\t        client_address_plus.addr = dhcps_lease.start_ip.addr;\r\n\t\t\t\t\t\t    } else {\r\n                                addr_tmp.addr = htonl(client_address.addr);\r\n                                addr_tmp.addr++;\r\n                                client_address_plus.addr = htonl(addr_tmp.addr);\r\n\t\t\t\t\t\t    }\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tPOOL_CHECK:\r\n\t\t\t\t\t\tif ((client_address.addr > dhcps_lease.end_ip.addr) || (ip_addr_isany(&client_address))){\r\n                            os_printf(\"client_address_plus.addr %x %d\\n\", client_address_plus.addr, system_get_free_heap_size());\r\n\t\t\t\t\t\t    if(pnode != NULL) {\r\n\t\t\t\t\t\t        node_remove_from_list(&plist,pnode);\r\n\t\t\t\t\t\t        os_free(pnode);\r\n\t\t\t\t\t\t        pnode = NULL;\r\n\t\t\t\t\t\t    }\r\n\r\n\t\t\t\t\t\t    if (pdhcps_pool != NULL) {\r\n\t\t\t\t\t\t        os_free(pdhcps_pool);\r\n\t\t\t\t\t\t        pdhcps_pool = NULL;\r\n\t\t\t\t\t\t    }\r\n//\t\t\t\t\t\t\tclient_address_plus.addr = dhcps_lease.start_ip.addr;\r\n\t\t\t\t\t\t\treturn 4;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tsint16_t ret = parse_options(&m->options[4], len);;\r\n\r\n\t\t\t\t\t\tif(ret == DHCPS_STATE_RELEASE) {\r\n\t\t\t\t\t\t    if(pnode != NULL) {\r\n\t\t\t\t\t\t        node_remove_from_list(&plist,pnode);\r\n\t\t\t\t\t\t        os_free(pnode);\r\n\t\t\t\t\t\t        pnode = NULL;\r\n\t\t\t\t\t\t    }\r\n\r\n\t\t\t\t\t\t    if (pdhcps_pool != NULL) {\r\n\t\t\t\t\t\t        os_free(pdhcps_pool);\r\n\t\t\t\t\t\t        pdhcps_pool = NULL;\r\n\t\t\t\t\t\t    }\r\n\t\t\t\t\t\t    os_memset(&client_address,0x0,sizeof(client_address));\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (wifi_softap_set_station_info(m->chaddr, &client_address) == false) {\r\n\t\t\t\t\t\t    return 0;\r\n\t\t\t\t\t\t}\r\n//\t                }\r\n\r\n#if DHCPS_DEBUG\r\n\t                os_printf(\"dhcps: xid changed\\n\");\r\n\t                os_printf(\"dhcps: client_address.addr = %x\\n\", client_address.addr);\r\n#endif\r\n\t               \r\n//\t            }\r\n\t            \r\n//\t        }\r\n\t        return ret;\r\n\t    }\r\n        return 0;\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\n/*\r\n * DHCP ��������ݰ���մ���ص�����˺�����LWIP UDPģ������ʱ������\r\n * ��Ҫ����udp_recv()������LWIP����ע��.\r\n *\r\n * @param arg\r\n * @param pcb ���յ�UDP��Ŀ��ƿ�?\r\n * @param p ���յ���UDP�е��������?\r\n * @param addr ���ʹ�UDP���Դ�����IP��ַ\r\n * @param port ���ʹ�UDP���Դ�����UDPͨ���˿ں�\r\n */\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic void ICACHE_FLASH_ATTR handle_dhcp(void *arg, \r\n\t\t\t\t\t\t\t\t\tstruct udp_pcb *pcb, \r\n\t\t\t\t\t\t\t\t\tstruct pbuf *p, \r\n\t\t\t\t\t\t\t\t\tstruct ip_addr *addr, \r\n\t\t\t\t\t\t\t\t\tuint16_t port)\r\n{\r\n\t\tstruct dhcps_msg *pmsg_dhcps = NULL;\r\n\t\tsint16_t tlen = 0;\r\n        u16_t i = 0;\r\n\t    u16_t dhcps_msg_cnt = 0;\r\n\t    u8_t *p_dhcps_msg = NULL;\r\n\t    u8_t *data = NULL;\r\n\r\n#if DHCPS_DEBUG\r\n    \tos_printf(\"dhcps: handle_dhcp-> receive a packet\\n\");\r\n#endif\r\n\t    if (p==NULL) return;\r\n\r\n\t    pmsg_dhcps = (struct dhcps_msg *)os_zalloc(sizeof(struct dhcps_msg));\r\n\t    if (NULL == pmsg_dhcps){\r\n\t    \tpbuf_free(p);\r\n\t    \treturn;\r\n\t    }\r\n\t    p_dhcps_msg = (u8_t *)pmsg_dhcps;\r\n\t\ttlen = p->tot_len;\r\n\t    data = p->payload;\r\n\r\n#if DHCPS_DEBUG\r\n\t    os_printf(\"dhcps: handle_dhcp-> p->tot_len = %d\\n\", tlen);\r\n\t    os_printf(\"dhcps: handle_dhcp-> p->len = %d\\n\", p->len);\r\n#endif\t\t\r\n\r\n\t    for(i=0; i<p->len; i++){\r\n\t        p_dhcps_msg[dhcps_msg_cnt++] = data[i];\r\n#if DHCPS_DEBUG\t\t\t\t\t\r\n\t\t\tos_printf(\"%02x \",data[i]);\r\n\t\t\tif((i+1)%16 == 0){\r\n\t\t\t\tos_printf(\"\\n\");\r\n\t\t\t}\r\n#endif\r\n\t    }\r\n\t\t\r\n\t\tif(p->next != NULL) {\r\n#if DHCPS_DEBUG\r\n\t        os_printf(\"dhcps: handle_dhcp-> p->next != NULL\\n\");\r\n\t        os_printf(\"dhcps: handle_dhcp-> p->next->tot_len = %d\\n\",p->next->tot_len);\r\n\t        os_printf(\"dhcps: handle_dhcp-> p->next->len = %d\\n\",p->next->len);\r\n#endif\r\n\t\t\t\r\n\t        data = p->next->payload;\r\n\t        for(i=0; i<p->next->len; i++){\r\n\t            p_dhcps_msg[dhcps_msg_cnt++] = data[i];\r\n#if DHCPS_DEBUG\t\t\t\t\t\r\n\t\t\t\tos_printf(\"%02x \",data[i]);\r\n\t\t\t\tif((i+1)%16 == 0){\r\n\t\t\t\t\tos_printf(\"\\n\");\r\n\t\t\t\t}\r\n#endif\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t/*\r\n\t     * DHCP �ͻ���������Ϣ����\r\n\t    */\r\n#if DHCPS_DEBUG\r\n    \tos_printf(\"dhcps: handle_dhcp-> parse_msg(p)\\n\");\r\n#endif\r\n\t\t\r\n        switch(parse_msg(pmsg_dhcps, tlen - 240)) {\r\n\r\n\t        case DHCPS_STATE_OFFER://1\r\n#if DHCPS_DEBUG            \r\n            \t os_printf(\"dhcps: handle_dhcp-> DHCPD_STATE_OFFER\\n\");\r\n#endif\t\t\t\r\n\t             send_offer(pmsg_dhcps);\r\n\t             break;\r\n\t        case DHCPS_STATE_ACK://3\r\n#if DHCPS_DEBUG\r\n            \t os_printf(\"dhcps: handle_dhcp-> DHCPD_STATE_ACK\\n\");\r\n#endif\t\t\t\r\n\t             send_ack(pmsg_dhcps);\r\n\t             break;\r\n\t        case DHCPS_STATE_NAK://4\r\n#if DHCPS_DEBUG            \r\n            \t os_printf(\"dhcps: handle_dhcp-> DHCPD_STATE_NAK\\n\");\r\n#endif\r\n\t             send_nak(pmsg_dhcps);\r\n\t             break;\r\n\t\t\tdefault :\r\n\t\t\t\t break;\r\n        }\r\n#if DHCPS_DEBUG\r\n    \tos_printf(\"dhcps: handle_dhcp-> pbuf_free(p)\\n\");\r\n#endif\r\n        pbuf_free(p);\r\n        os_free(pmsg_dhcps);\r\n        pmsg_dhcps = NULL;\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\nstatic void ICACHE_FLASH_ATTR wifi_softap_init_dhcps_lease(uint32 ip)\r\n{\r\n\tuint32 softap_ip = 0,local_ip = 0;\r\n\tuint32 start_ip = 0;\r\n\tuint32 end_ip = 0;\r\n//\tif (dhcps_lease_flag) {\r\n\tif (dhcps_lease.enable == TRUE) {\r\n\t\tsoftap_ip = htonl(ip);\r\n\t\tstart_ip = htonl(dhcps_lease.start_ip.addr);\r\n\t\tend_ip = htonl(dhcps_lease.end_ip.addr);\r\n\t\t/*config ip information can't contain local ip*/\r\n\t\tif ((start_ip <= softap_ip) && (softap_ip <= end_ip)) {\r\n\t\t\tdhcps_lease.enable = FALSE;\r\n\t\t} else {\r\n\t\t\t/*config ip information must be in the same segment as the local ip*/\r\n\t\t\tsoftap_ip >>= 8;\r\n\t\t\tif (((start_ip >> 8 != softap_ip) || (end_ip >> 8 != softap_ip))\r\n\t\t\t\t\t|| (end_ip - start_ip > DHCPS_MAX_LEASE)) {\r\n\t\t\t\tdhcps_lease.enable = FALSE;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tif (dhcps_lease.enable == FALSE) {\r\n\t\tlocal_ip = softap_ip = htonl(ip);\r\n\t\tsoftap_ip &= 0xFFFFFF00;\r\n\t\tlocal_ip &= 0xFF;\r\n\t\tif (local_ip >= 0x80)\r\n\t\t\tlocal_ip -= DHCPS_MAX_LEASE;\r\n\t\telse\r\n\t\t\tlocal_ip ++;\r\n\r\n\t\tos_bzero(&dhcps_lease, sizeof(dhcps_lease));\r\n\t\tdhcps_lease.start_ip.addr = softap_ip | local_ip;\r\n\t\tdhcps_lease.end_ip.addr = softap_ip | (local_ip + DHCPS_MAX_LEASE - 1);\r\n\t\tdhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr);\r\n\t\tdhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr);\r\n\t}\r\n//\tdhcps_lease.start_ip.addr = htonl(dhcps_lease.start_ip.addr);\r\n//\tdhcps_lease.end_ip.addr= htonl(dhcps_lease.end_ip.addr);\r\n//\tos_printf(\"start_ip = 0x%x, end_ip = 0x%x\\n\",dhcps_lease.start_ip, dhcps_lease.end_ip);\r\n}\r\n///////////////////////////////////////////////////////////////////////////////////\r\nvoid ICACHE_FLASH_ATTR dhcps_start(struct ip_info *info)\r\n{\r\n\tstruct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01);\r\n    \r\n\tif(apnetif->dhcps_pcb != NULL) {\r\n        udp_remove(apnetif->dhcps_pcb);\r\n    }\r\n\r\n\tpcb_dhcps = udp_new();\r\n\tif (pcb_dhcps == NULL || info ==NULL) {\r\n\t\tos_printf(\"dhcps_start(): could not obtain pcb\\n\");\r\n\t}\r\n\r\n\tapnetif->dhcps_pcb = pcb_dhcps;\r\n\r\n\tIP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255);\r\n\r\n\tserver_address = info->ip;\r\n\twifi_softap_init_dhcps_lease(server_address.addr);\r\n\tclient_address_plus.addr = dhcps_lease.start_ip.addr;\r\n\r\n\tudp_bind(pcb_dhcps, IP_ADDR_ANY, DHCPS_SERVER_PORT);\r\n\tudp_recv(pcb_dhcps, handle_dhcp, NULL);\r\n#if DHCPS_DEBUG\r\n\tos_printf(\"dhcps:dhcps_start->udp_recv function Set a receive callback handle_dhcp for UDP_PCB pcb_dhcps\\n\");\r\n#endif\r\n\t\t\r\n}\r\n\r\nvoid ICACHE_FLASH_ATTR dhcps_stop(void)\r\n{\r\n\tstruct netif * apnetif = (struct netif *)eagle_lwip_getif(0x01);\r\n\r\n\tudp_disconnect(pcb_dhcps);\r\n//\tdhcps_lease_flag = true;\r\n    if(apnetif->dhcps_pcb != NULL) {\r\n        udp_remove(apnetif->dhcps_pcb);\r\n        apnetif->dhcps_pcb = NULL;\r\n    }\r\n\r\n\t//udp_remove(pcb_dhcps);\r\n\tlist_node *pnode = NULL;\r\n\tlist_node *pback_node = NULL;\r\n\tpnode = plist;\r\n\twhile (pnode != NULL) {\r\n\t\tpback_node = pnode;\r\n\t\tpnode = pback_node->pnext;\r\n\t\tnode_remove_from_list(&plist, pback_node);\r\n\t\tos_free(pback_node->pnode);\r\n\t\tpback_node->pnode = NULL;\r\n\t\tos_free(pback_node);\r\n\t\tpback_node = NULL;\r\n\t}\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : wifi_softap_set_dhcps_lease\r\n * Description  : set the lease information of DHCP server\r\n * Parameters   : please -- Additional argument to set the lease information,\r\n * \t\t\t\t\t\t\tLittle-Endian.\r\n * Returns      : true or false\r\n*******************************************************************************/\r\nbool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease(struct dhcps_lease *please)\r\n{\r\n\tstruct ip_info info;\r\n\tuint32 softap_ip = 0;\r\n\tuint32 start_ip = 0;\r\n\tuint32 end_ip = 0;\r\n\r\n\tuint8 opmode = wifi_get_opmode();\r\n\r\n\tif (opmode == STATION_MODE || opmode == NULL_MODE) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (please == NULL || wifi_softap_dhcps_status() == DHCP_STARTED)\r\n\t\treturn false;\r\n\r\n\tif(please->enable) {\r\n\t\tos_bzero(&info, sizeof(struct ip_info));\r\n\t\twifi_get_ip_info(SOFTAP_IF, &info);\r\n\t\tsoftap_ip = htonl(info.ip.addr);\r\n\t\tstart_ip = htonl(please->start_ip.addr);\r\n\t\tend_ip = htonl(please->end_ip.addr);\r\n\r\n\t\t/*config ip information can't contain local ip*/\r\n\t\tif ((start_ip <= softap_ip) && (softap_ip <= end_ip))\r\n\t\t\treturn false;\r\n\r\n\t\t/*config ip information must be in the same segment as the local ip*/\r\n\t\tsoftap_ip >>= 8;\r\n\t\tif ((start_ip >> 8 != softap_ip)\r\n\t\t\t\t|| (end_ip >> 8 != softap_ip)) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tif (end_ip - start_ip > DHCPS_MAX_LEASE)\r\n\t\t\treturn false;\r\n\r\n\t\tos_bzero(&dhcps_lease, sizeof(dhcps_lease));\r\n//\t\tdhcps_lease.start_ip.addr = start_ip;\r\n//\t\tdhcps_lease.end_ip.addr = end_ip;\r\n\t\tdhcps_lease.start_ip.addr = please->start_ip.addr;\r\n\t\tdhcps_lease.end_ip.addr = please->end_ip.addr;\r\n\t}\r\n\tdhcps_lease.enable = please->enable;\r\n//\tdhcps_lease_flag = false;\r\n\treturn true;\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : wifi_softap_get_dhcps_lease\r\n * Description  : get the lease information of DHCP server\r\n * Parameters   : please -- Additional argument to get the lease information,\r\n * \t\t\t\t\t\t\tLittle-Endian.\r\n * Returns      : true or false\r\n*******************************************************************************/\r\nbool ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease(struct dhcps_lease *please)\r\n{\r\n\tuint8 opmode = wifi_get_opmode();\r\n\r\n\tif (opmode == STATION_MODE || opmode == NULL_MODE) {\r\n\t\treturn false;\r\n\t}\r\n\r\n\tif (NULL == please)\r\n\t\treturn false;\r\n\r\n//\tif (dhcps_lease_flag){\r\n\tif (dhcps_lease.enable == FALSE){\r\n\t\tif (wifi_softap_dhcps_status() == DHCP_STOPPED)\r\n\t\t\treturn false;\r\n\t} else {\r\n//\t\tos_bzero(please, sizeof(dhcps_lease));\r\n//\t\tif (wifi_softap_dhcps_status() == DHCP_STOPPED){\r\n//\t\t\tplease->start_ip.addr = htonl(dhcps_lease.start_ip.addr);\r\n//\t\t\tplease->end_ip.addr = htonl(dhcps_lease.end_ip.addr);\r\n//\t\t}\r\n\t}\r\n\r\n//\tif (wifi_softap_dhcps_status() == DHCP_STARTED){\r\n//\t\tos_bzero(please, sizeof(dhcps_lease));\r\n//\t\tplease->start_ip.addr = dhcps_lease.start_ip.addr;\r\n//\t\tplease->end_ip.addr = dhcps_lease.end_ip.addr;\r\n//\t}\r\n\tplease->start_ip.addr = dhcps_lease.start_ip.addr;\r\n\tplease->end_ip.addr = dhcps_lease.end_ip.addr;\r\n\treturn true;\r\n}\r\n\r\nstatic void ICACHE_FLASH_ATTR kill_oldest_dhcps_pool(void)\r\n{\r\n\tlist_node *pre = NULL, *p = NULL;\r\n\tlist_node *minpre = NULL, *minp = NULL;\r\n\tstruct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL;\r\n\tpre = plist;\r\n\tp = pre->pnext;\r\n\tminpre = pre;\r\n\tminp = p;\r\n\twhile (p != NULL){\r\n\t\tpdhcps_pool = p->pnode;\r\n\t\tpmin_pool = minp->pnode;\r\n\t\tif (pdhcps_pool->lease_timer < pmin_pool->lease_timer){\r\n\t\t\tminp = p;\r\n\t\t\tminpre = pre;\r\n\t\t}\r\n\t\tpre = p;\r\n\t\tp = p->pnext;\r\n\t}\r\n\tminpre->pnext = minp->pnext;\r\n\tos_free(minp->pnode);\r\n\tminp->pnode = NULL;\r\n\tos_free(minp);\r\n\tminp = NULL;\r\n}\r\n\r\nvoid ICACHE_FLASH_ATTR dhcps_coarse_tmr(void)\r\n{\r\n\tuint8 num_dhcps_pool = 0;\r\n\tlist_node *pback_node = NULL;\r\n\tlist_node *pnode = NULL;\r\n\tstruct dhcps_pool *pdhcps_pool = NULL;\r\n\tpnode = plist;\r\n\twhile (pnode != NULL) {\r\n\t\tpdhcps_pool = pnode->pnode;\r\n\t\tpdhcps_pool->lease_timer --;\r\n\t\tif (pdhcps_pool->lease_timer == 0){\r\n\t\t\tpback_node = pnode;\r\n\t\t\tpnode = pback_node->pnext;\r\n\t\t\tnode_remove_from_list(&plist,pback_node);\r\n\t\t\tos_free(pback_node->pnode);\r\n\t\t\tpback_node->pnode = NULL;\r\n\t\t\tos_free(pback_node);\r\n\t\t\tpback_node = NULL;\r\n\t\t} else {\r\n\t\t\tpnode = pnode ->pnext;\r\n\t\t\tnum_dhcps_pool ++;\r\n\t\t}\r\n\t}\r\n\r\n\tif (num_dhcps_pool >= MAX_STATION_NUM)\r\n\t\tkill_oldest_dhcps_pool();\r\n}\r\n\r\nbool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg)\r\n{\r\n\tbool offer_flag = true;\r\n\tuint8 option = 0;\r\n\tif (optarg == NULL && wifi_softap_dhcps_status() == false)\r\n\t\treturn false;\r\n\r\n\tif (level <= OFFER_START || level >= OFFER_END)\r\n\t\treturn false;\r\n\r\n\tswitch (level){\r\n\t\tcase OFFER_ROUTER:\r\n\t\t\toffer = (*(uint8 *)optarg) & 0x01;\r\n\t\t\toffer_flag = true;\r\n\t\t\tbreak;\r\n\t\tdefault :\r\n\t\t\toffer_flag = false;\r\n\t\t\tbreak;\r\n\t}\r\n\treturn offer_flag;\r\n}\r\n\r\nbool ICACHE_FLASH_ATTR wifi_softap_set_dhcps_lease_time(uint32 minute)\r\n{\r\n    uint8 opmode = wifi_get_opmode();\r\n\r\n    if (opmode == STATION_MODE || opmode == NULL_MODE) {\r\n        return false;\r\n    }\r\n\r\n    if (wifi_softap_dhcps_status() == DHCP_STARTED) {\r\n        return false;\r\n    }\r\n\r\n    if(minute == 0) {\r\n        return false;\r\n    }\r\n    dhcps_lease_time = minute;\r\n    return true;\r\n}\r\n\r\nbool ICACHE_FLASH_ATTR wifi_softap_reset_dhcps_lease_time(void)\r\n{\r\n    uint8 opmode = wifi_get_opmode();\r\n\r\n    if (opmode == STATION_MODE || opmode == NULL_MODE) {\r\n        return false;\r\n    }\r\n\r\n    if (wifi_softap_dhcps_status() == DHCP_STARTED) {\r\n        return false;\r\n    }\r\n    dhcps_lease_time = DHCPS_LEASE_TIME_DEF;\r\n    return true;\r\n}\r\n\r\nuint32 ICACHE_FLASH_ATTR wifi_softap_get_dhcps_lease_time(void) // minute\r\n{\r\n    return dhcps_lease_time;\r\n}\r\n"
  },
  {
    "path": "app/lwip/app/espconn.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: espconn.c\n *\n * Description: espconn interface for user\n *\n * Modification history:\n *     2014/3/31, v1.0 create this file.\n*******************************************************************************/\n\n#include \"lwip/netif.h\"\n#include \"lwip/inet.h\"\n#include \"netif/etharp.h\"\n#include \"lwip/tcp.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/init.h\"\n#include \"ets_sys.h\"\n#include \"os_type.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\n\n#include \"lwip/app/espconn_tcp.h\"\n#include \"lwip/app/espconn_udp.h\"\n#include \"lwip/app/espconn.h\"\n#include \"user_interface.h\"\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\nespconn_msg *plink_active = NULL;\nespconn_msg *pserver_list = NULL;\nremot_info premot[linkMax];\n\nstruct espconn_packet pktinfo[2];\n\nstatic uint8 espconn_tcp_get_buf_count(espconn_buf *pesp_buf);\n/******************************************************************************\n * FunctionName : espconn_copy_partial\n * Description  : reconnect with host\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_copy_partial(struct espconn *pesp_dest, struct espconn *pesp_source)\n{\n\tpesp_dest->type = pesp_source->type;\n\tpesp_dest->state = pesp_source->state;\n\tif (pesp_source->type == ESPCONN_TCP){\n\t\tpesp_dest->proto.tcp->remote_port = pesp_source->proto.tcp->remote_port;\n\t\tpesp_dest->proto.tcp->local_port = pesp_source->proto.tcp->local_port;\n\t\tos_memcpy(pesp_dest->proto.tcp->remote_ip, pesp_source->proto.tcp->remote_ip, 4);\n\t\tos_memcpy(pesp_dest->proto.tcp->local_ip, pesp_source->proto.tcp->local_ip, 4);\n\t\tpesp_dest->proto.tcp->connect_callback = pesp_source->proto.tcp->connect_callback;\n\t\tpesp_dest->proto.tcp->reconnect_callback = pesp_source->proto.tcp->reconnect_callback;\n\t\tpesp_dest->proto.tcp->disconnect_callback = pesp_source->proto.tcp->disconnect_callback;\n\t} else {\n\t\tpesp_dest->proto.udp->remote_port = pesp_source->proto.udp->remote_port;\n\t\tpesp_dest->proto.udp->local_port = pesp_source->proto.udp->local_port;\n\t\tos_memcpy(pesp_dest->proto.udp->remote_ip, pesp_source->proto.udp->remote_ip, 4);\n\t\tos_memcpy(pesp_dest->proto.udp->local_ip, pesp_source->proto.udp->local_ip, 4);\n\t}\n\tpesp_dest->recv_callback = pesp_source->recv_callback;\n\tpesp_dest->sent_callback = pesp_source->sent_callback;\n\tpesp_dest->link_cnt = pesp_source->link_cnt;\n\tpesp_dest->reverse = pesp_source->reverse;\n}\n\n/******************************************************************************\n * FunctionName : espconn_copy_partial\n * Description  : insert the node to the active connection list\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_list_creat(espconn_msg **phead, espconn_msg* pinsert)\n{\n\tespconn_msg *plist = NULL;\n//\tespconn_msg *ptest = NULL;\n\tif (*phead == NULL)\n\t\t*phead = pinsert;\n\telse {\n\t\tplist = *phead;\n\t\twhile (plist->pnext != NULL) {\n\t\t\tplist = plist->pnext;\n\t\t}\n\t\tplist->pnext = pinsert;\n\t}\n\tpinsert->pnext = NULL;\n\n/*\tptest = *phead;\n\twhile(ptest != NULL){\n\t\tos_printf(\"espconn_list_creat %p\\n\", ptest);\n\t\tptest = ptest->pnext;\n\t}*/\n}\n\n/******************************************************************************\n * FunctionName : espconn_list_delete\n * Description  : remove the node from the active connection list\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_list_delete(espconn_msg **phead, espconn_msg* pdelete)\n{\n\tespconn_msg *plist = NULL;\n//\tespconn_msg *ptest = NULL;\n\tplist = *phead;\n\tif (plist == NULL){\n\t\t*phead = NULL;\n\t} else {\n\t\tif (plist == pdelete){\n\t\t\t*phead = plist->pnext;\n\t\t} else {\n\t\t\twhile (plist != NULL) {\n\t\t\t\tif (plist->pnext == pdelete){\n\t\t\t\t\tplist->pnext = pdelete->pnext;\n\t\t\t\t}\n\t\t\t\tplist = plist->pnext;\n\t\t\t}\n\t\t}\n\t}\n/*\tptest = *phead;\n\twhile(ptest != NULL){\n\t\tos_printf(\"espconn_list_delete %p\\n\", ptest);\n\t\tptest = ptest->pnext;\n\t}*/\n}\n\n/******************************************************************************\n * FunctionName : espconn_pbuf_create\n * Description  : insert the node to the active connection list\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_pbuf_create(espconn_buf **phead, espconn_buf* pinsert)\n{\n\tespconn_buf *plist = NULL;\n\n\tif (*phead == NULL)\n\t\t*phead = pinsert;\n\telse {\n\t\tplist = *phead;\n\t\twhile (plist->pnext != NULL) {\n\t\t\tplist = plist->pnext;\n\t\t}\n\t\tplist->pnext = pinsert;\n\t}\n\tpinsert->pnext = NULL;\n}\n\n/******************************************************************************\n * FunctionName : espconn_pbuf_delete\n * Description  : remove the node from the active connection list\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_pbuf_delete(espconn_buf **phead, espconn_buf* pdelete)\n{\n\tespconn_buf *plist = NULL;\n\n\tplist = *phead;\n\tif (plist == NULL){\n\t\t*phead = NULL;\n\t} else {\n\t\tif (plist == pdelete){\n\t\t\t*phead = plist->pnext;\n\t\t} else {\n\t\t\twhile (plist != NULL) {\n\t\t\t\tif (plist->pnext == pdelete){\n\t\t\t\t\tplist->pnext = pdelete->pnext;\n\t\t\t\t}\n\t\t\t\tplist = plist->pnext;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_find_connection\n * Description  : Initialize the server: set up a listening PCB and bind it to\n *                the defined port\n * Parameters   : espconn -- the espconn used to build server\n * Returns      : true or false\n *******************************************************************************/\nbool ICACHE_FLASH_ATTR espconn_find_connection(struct espconn *pespconn, espconn_msg **pnode)\n{\n\tespconn_msg *plist = NULL;\n\tstruct ip_addr ip_remot;\n\tstruct ip_addr ip_list;\n\n    if (pespconn == NULL)\n\t\treturn false;\n\n    /*find the active connection node*/\n    for (plist = plink_active; plist != NULL; plist = plist->pnext){\n\t\tif (pespconn == plist->pespconn) {\n\t\t\t*pnode = plist;\n\t\t\treturn true;\n\t\t}\n\t}\n\n    /*find the active server node*/\n    for (plist = pserver_list; plist != NULL; plist = plist->pnext){\n    \tif (pespconn == plist->pespconn) {\n\t\t\tif (pespconn->proto.tcp == NULL)\n\t\t\t\treturn false;\n\n\t\t\tIP4_ADDR(&ip_remot, pespconn->proto.tcp->remote_ip[0],\n\t\t\t\t\tpespconn->proto.tcp->remote_ip[1],\n\t\t\t\t\tpespconn->proto.tcp->remote_ip[2],\n\t\t\t\t\tpespconn->proto.tcp->remote_ip[3]);\n\t\t\tif ((ip_remot.addr == IPADDR_ANY) || (pespconn->proto.tcp->remote_port == 0))\n\t\t\t\treturn false;\n\n\t\t\t/*find the active connection node*/\n\t\t\tfor (plist = plink_active; plist != NULL; plist = plist->pnext){\n\t\t\t\tIP4_ADDR(&ip_list, plist->pcommon.remote_ip[0],\n\t\t\t\t\t\tplist->pcommon.remote_ip[1], plist->pcommon.remote_ip[2],\n\t\t\t\t\t\tplist->pcommon.remote_ip[3]);\n\t\t\t\tif ((ip_list.addr == ip_remot.addr)\t&& (pespconn->proto.tcp->remote_port == plist->pcommon.remote_port)) {\n\t\t\t\t\t*pnode = plist;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n    return false;\n}\n\n/******************************************************************************\n * FunctionName : espconn_get_acticve_num\n * Description  : get the count of simulatenously active connections\n * Parameters   : type -- the type\n * Returns      : the count of simulatenously active connections\n *******************************************************************************/\nstatic uint8 ICACHE_FLASH_ATTR\nespconn_get_acticve_num(uint8 type)\n{\n\tespconn_msg *plist = NULL;\n\tuint8 num_tcp_active = 0;\n\n\tfor (plist = plink_active; plist != NULL; plist = plist->pnext) {\n\t\tif (plist->pespconn != NULL && plist->pespconn->type == type) {\n\t\t\tnum_tcp_active++;\n\t\t}\n\t}\n\n\treturn num_tcp_active;\n}\n\n/******************************************************************************\n * FunctionName : espconn_connect\n * Description  : The function given as the connect\n * Parameters   : espconn -- the espconn used to listen the connection\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_connect(struct espconn *espconn)\n{\n\tstruct ip_addr ipaddr;\n\tstruct ip_info ipinfo;\n\tuint8 connect_status = 0;\n\tsint8 value = ESPCONN_OK;\n\tespconn_msg *plist = NULL;\n\tremot_info *pinfo = NULL;\n\n    if (espconn == NULL) {\n        return ESPCONN_ARG;\n    } else if (espconn ->type != ESPCONN_TCP)\n    \treturn ESPCONN_ARG;\n\n    /*Check the active node count whether is the limit or not*/\n    if (espconn_get_acticve_num(ESPCONN_TCP) >= espconn_tcp_get_max_con())\n    \treturn ESPCONN_ISCONN;\n\n    /*Check the IP address whether is zero or not in different mode*/\n    if (wifi_get_opmode() == ESPCONN_STA){\n    \twifi_get_ip_info(STA_NETIF,&ipinfo);\n    \tif (ipinfo.ip.addr == 0){\n   \t \t\treturn ESPCONN_RTE;\n   \t \t}\n    } else if(wifi_get_opmode() == ESPCONN_AP){\n    \twifi_get_ip_info(AP_NETIF,&ipinfo);\n    \tif (ipinfo.ip.addr == 0){\n    \t\treturn ESPCONN_RTE;\n    \t}\n    } else if(wifi_get_opmode() == ESPCONN_AP_STA){\n    \tIP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0],\n    \t    \t    \t\tespconn->proto.tcp->remote_ip[1],\n    \t    \t    \t\tespconn->proto.tcp->remote_ip[2],\n    \t    \t    \t\tespconn->proto.tcp->remote_ip[3]);\n    \tipaddr.addr <<= 8;\n    \twifi_get_ip_info(AP_NETIF,&ipinfo);\n    \tipinfo.ip.addr <<= 8;\n    \tespconn_printf(\"softap_addr = %x, remote_addr = %x\\n\", ipinfo.ip.addr, ipaddr.addr);\n\n    \tif (ipaddr.addr != ipinfo.ip.addr){\n    \t\tconnect_status = wifi_station_get_connect_status();\n\t\t\tif (connect_status == STATION_GOT_IP){\n\t\t\t\twifi_get_ip_info(STA_NETIF,&ipinfo);\n\t\t\t\tif (ipinfo.ip.addr == 0)\n\t\t\t\t\treturn ESPCONN_RTE;\n\t\t\t} else if (connect_status == STATION_IDLE){\n\t\t\t\treturn ESPCONN_RTE;\n\t\t\t} else {\n\t\t\t\treturn connect_status;\n\t\t\t}\n    \t}\n    }\n\n    /*check the active node information whether is the same as the entity or not*/\n    for (plist = plink_active; plist != NULL; plist = plist->pnext){\n    \tif (plist->pespconn && plist->pespconn->type == ESPCONN_TCP){\n    \t\tif (espconn->proto.tcp->local_port == plist->pespconn->proto.tcp->local_port){\n    \t\t\treturn ESPCONN_ISCONN;\n    \t\t}\n    \t}\n    }\n\n    value = espconn_tcp_client(espconn);\n\n    return value;\n}\n\n/******************************************************************************\n * FunctionName : espconn_create\n * Description  : sent data for client or server\n * Parameters   : espconn -- espconn to the data transmission\n * Returns      : result\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_create(struct espconn *espconn)\n{\n\tsint8 value = ESPCONN_OK;\n\tespconn_msg *plist = NULL;\n\n\tif (espconn == NULL) {\n\t\treturn ESPCONN_ARG;\n\t} else if (espconn ->type != ESPCONN_UDP){\n\t\treturn ESPCONN_ARG;\n\t}\n\n\t/*check the active node information whether is the same as the entity or not*/\n\tfor (plist = plink_active; plist != NULL; plist = plist->pnext){\n\t\tif (plist->pespconn && plist->pespconn->type == ESPCONN_UDP){\n\t\t\tif (espconn->proto.udp->local_port == plist->pespconn->proto.udp->local_port){\n\t\t\t\treturn ESPCONN_ISCONN;\n\t\t\t}\n\t\t}\n\t}\n\n\tvalue = espconn_udp_server(espconn);\n\n\treturn value;\n}\n\n/******************************************************************************\n * FunctionName : espconn_sent\n * Description  : sent data for client or server\n * Parameters   : espconn -- espconn to set for client or server\n *                psent -- data to send\n *                length -- length of data to send\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_sent(struct espconn *espconn, uint8 *psent, uint16 length)\n{\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n\terr_t error = ESPCONN_OK;\n\t\n    if (espconn == NULL || psent == NULL || length == 0) {\n        return ESPCONN_ARG;\n    }\n\n\t/*Find the node depend on the espconn message*/\n\tvalue = espconn_find_connection(espconn, &pnode);\n\n    if (value){\n    \tespconn ->state = ESPCONN_WRITE;\n\t\tswitch (espconn ->type) {\n\t\t\tcase ESPCONN_TCP:\n\t\t\t\t/* calling sent function frequently,make sure last packet has been backup or sent fully*/\n\t\t\t\tif (pnode->pcommon.write_flag){\n\t\t\t\t\tespconn_buf *pbuf = NULL;\n\t\t\t\t\t/*If total number of espconn_buf on the unsent lists exceeds the set maximum, return an error */\n\t\t\t\t\tif (espconn_copy_enabled(pnode)){\n\t\t\t\t\t\tif (espconn_tcp_get_buf_count(pnode->pcommon.pbuf) >= pnode ->pcommon.pbuf_num)\n\t\t\t\t\t\t\treturn ESPCONN_MAXNUM;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstruct tcp_pcb *pcb = pnode->pcommon.pcb;\n\t\t\t\t\t\tif (pcb->snd_queuelen >= TCP_SND_QUEUELEN)\n\t\t\t\t\t\t\treturn ESPCONN_MAXNUM;\n\t\t\t\t\t}\n\n\t\t\t\t\tpbuf = (espconn_buf*) os_zalloc(sizeof(espconn_buf));\n\t\t\t\t\tif (pbuf == NULL)\n\t\t\t\t\t\treturn ESPCONN_MEM;\n\t\t\t\t\telse {\n\t\t\t\t\t\t/*Backup the application packet information for send more data*/\n\t\t\t\t\t\tpbuf->payload = psent;\n\t\t\t\t\t\tpbuf->punsent = pbuf->payload;\n\t\t\t\t\t\tpbuf->unsent = length;\n\t\t\t\t\t\tpbuf->len = length;\n\t\t\t\t\t\t/*insert the espconn_pbuf to the list*/\n\t\t\t\t\t\tespconn_pbuf_create(&pnode->pcommon.pbuf, pbuf);\n\t\t\t\t\t\tif (pnode->pcommon.ptail == NULL)\n\t\t\t\t\t\t\tpnode->pcommon.ptail = pbuf;\n\t\t\t\t\t}\n\t\t\t\t\t/*when set the data copy option. change the flag for next packet*/\n\t\t\t\t\tif (espconn_copy_disabled(pnode))\n\t\t\t\t\t\tpnode->pcommon.write_flag = false;\n\t\t\t\t\terror = espconn_tcp_write(pnode);\n//\t\t\t\t\tif (error != ESPCONN_OK){\n//\t\t\t\t\t\t/*send the application packet fail,\n//\t\t\t\t\t\t * ensure that each allocated is deleted*/\n//\t\t\t\t\t\tespconn_pbuf_delete(&pnode->pcommon.pbuf, pbuf);\n//\t\t\t\t\t\tos_free(pbuf);\n//\t\t\t\t\t\tpbuf = NULL;\n//\t\t\t\t\t}\n\t\t\t\t\treturn error;\n\t\t\t\t} else\n\t\t\t\t\treturn ESPCONN_ARG;\n\t\t\t\tbreak;\n\n\t\t\tcase ESPCONN_UDP:\n\t\t\t\treturn espconn_udp_sent(pnode, psent, length);\n\t\t\t\tbreak;\n\n\t\t\tdefault :\n\t\t\t\tbreak;\n\t\t}\n    }\n    return ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_sendto\n * Description  : send data for UDP\n * Parameters   : espconn -- espconn to set for UDP\n *                psent -- data to send\n *                length -- length of data to send\n * Returns      : error\n*******************************************************************************/\nsint16 ICACHE_FLASH_ATTR\nespconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length)\n{\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n\terr_t error = ESPCONN_OK;\n\n\tif (espconn == NULL || psent == NULL || length == 0) {\n\t\treturn ESPCONN_ARG;\n\t}\n\n\t/*Find the node depend on the espconn message*/\n\tvalue = espconn_find_connection(espconn, &pnode);\n\tif (value && espconn->type == ESPCONN_UDP)\n\t\treturn espconn_udp_sendto(pnode, psent, length);\n\telse\n\t\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_send\n * Description  : sent data for client or server\n * Parameters   : espconn -- espconn to set for client or server\n *                psent -- data to send\n *                length -- length of data to send\n * Returns      : none\n*******************************************************************************/\n\nsint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length) __attribute__((alias(\"espconn_sent\")));\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_wnd\n * Description  : get the window size of simulatenously active TCP connections\n * Parameters   : none\n * Returns      : the number of TCP_MSS active TCP connections\n*******************************************************************************/\nuint8 ICACHE_FLASH_ATTR espconn_tcp_get_wnd(void)\n{\n\tuint8 tcp_num = 0;\n\n\ttcp_num = (TCP_WND / TCP_MSS);\n\n\treturn tcp_num;\n}\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_con\n * Description  : set the window size simulatenously active TCP connections\n * Parameters   : num -- the number of TCP_MSS\n * Returns      : ESPCONN_ARG -- Illegal argument\n * \t\t\t\t  ESPCONN_OK  -- No error\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_tcp_set_wnd(uint8 num)\n{\n\tif (num == 0 || num > linkMax)\n\t\treturn ESPCONN_ARG;\n\n\tTCP_WND = (num * TCP_MSS);\n\treturn ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_mss\n * Description  : get the mss size of simulatenously active TCP connections\n * Parameters   : none\n * Returns      : the size of TCP_MSS active TCP connections\n*******************************************************************************/\nuint16 ICACHE_FLASH_ATTR espconn_tcp_get_mss(void)\n{\n\tuint16 tcp_num = 0;\n\n\ttcp_num = TCP_MSS;\n\n\treturn tcp_num;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_max_con\n * Description  : get the number of simulatenously active TCP connections\n * Parameters   : espconn -- espconn to set the connect callback\n * Returns      : none\n*******************************************************************************/\nuint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_con(void)\n{\n\tuint8 tcp_num = 0;\n\n\ttcp_num = MEMP_NUM_TCP_PCB;\n\n\treturn tcp_num;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_con\n * Description  : set the number of simulatenously active TCP connections\n * Parameters   : espconn -- espconn to set the connect callback\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_con(uint8 num)\n{\n\tif (num == 0 || num > linkMax)\n\t\treturn ESPCONN_ARG;\n\n\tMEMP_NUM_TCP_PCB = num;\n\treturn ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_max_retran\n * Description  : get the Maximum number of retransmissions of data active TCP connections\n * Parameters   : none\n * Returns      : the Maximum number of retransmissions\n*******************************************************************************/\nuint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_retran(void)\n{\n\tuint8 tcp_num = 0;\n\n\ttcp_num = TCP_MAXRTX;\n\n\treturn tcp_num;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_retran\n * Description  : set the Maximum number of retransmissions of data active TCP connections\n * Parameters   : num -- the Maximum number of retransmissions\n * Returns      : result\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_retran(uint8 num)\n{\n\tif (num == 0 || num > 12)\n\t\treturn ESPCONN_ARG;\n\n\tTCP_MAXRTX = num;\n\treturn ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_max_syn\n * Description  : get the Maximum number of retransmissions of SYN segments\n * Parameters   : none\n * Returns      : the Maximum number of retransmissions\n*******************************************************************************/\nuint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_syn(void)\n{\n\tuint8 tcp_num = 0;\n\n\ttcp_num = TCP_SYNMAXRTX;\n\n\treturn tcp_num;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_syn\n * Description  : set the Maximum number of retransmissions of SYN segments\n * Parameters   : num -- the Maximum number of retransmissions\n * Returns      : result\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_syn(uint8 num)\n{\n\tif (num == 0 || num > 12)\n\t\treturn ESPCONN_ARG;\n\n\tTCP_SYNMAXRTX = num;\n\treturn ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_max_con_allow\n * Description  : get the count of simulatenously active connections on the server\n * Parameters   : espconn -- espconn to get the count\n * Returns      : result\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_tcp_get_max_con_allow(struct espconn *espconn)\n{\n\tespconn_msg *pget_msg = NULL;\n\tif ((espconn == NULL) || (espconn->type == ESPCONN_UDP))\n\t\treturn ESPCONN_ARG;\n\n\tpget_msg = pserver_list;\n\twhile (pget_msg != NULL){\n\t\tif (pget_msg->pespconn == espconn){\n\t\t\treturn pget_msg->count_opt;\n\t\t}\n\t\tpget_msg = pget_msg->pnext;\n\t}\n\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_max_con_allow\n * Description  : set the count of simulatenously active connections on the server\n * Parameters   : espconn -- espconn to set the count\n * Returns      : result\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num)\n{\n\tespconn_msg *pset_msg = NULL;\n\tif ((espconn == NULL) || (num > MEMP_NUM_TCP_PCB) || (espconn->type == ESPCONN_UDP))\n\t\treturn ESPCONN_ARG;\n\n\tpset_msg = pserver_list;\n\twhile (pset_msg != NULL){\n\t\tif (pset_msg->pespconn == espconn){\n\t\t\tpset_msg->count_opt = num;\n\t\t\treturn ESPCONN_OK;\n\t\t}\n\t\tpset_msg = pset_msg->pnext;\n\t}\n\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_set_buf_count\n * Description  : set the total number of espconn_buf on the unsent lists for one\n * \t\t\t\t  activate connection\n * Parameters   : espconn -- espconn to set the count\n * \t\t\t\t  num -- the total number of espconn_buf\n * Returns      : result\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_tcp_set_buf_count(struct espconn *espconn, uint8 num)\n{\n\tespconn_msg *plist = NULL;\n\tif (espconn == NULL || (num > TCP_SND_QUEUELEN))\n\t\treturn ESPCONN_ARG;\n\n\t/*find the node from the active connection list*/\n\tfor (plist = plink_active; plist != NULL; plist = plist->pnext){\n\t\tif (plist->pespconn && plist->pespconn == espconn && espconn->type == ESPCONN_TCP){\n\t\t\tplist->pcommon.pbuf_num = num;\n\t\t\treturn ESPCONN_OK;\n\t\t}\n\t}\n\n\tif (plist == NULL)\n\t\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_get_buf_count\n * Description  : get the count of the current node which has espconn_buf\n * Parameters   : pesp_buf -- the list head of espconn_buf type\n * Returns      : the count of the current node which has espconn_buf\n*******************************************************************************/\nstatic uint8 ICACHE_FLASH_ATTR espconn_tcp_get_buf_count(espconn_buf *pesp_buf)\n{\n\tespconn_buf *pbuf_list = pesp_buf;\n\tuint8 pbuf_num = 0;\n\n\t/*polling the list get the count of the current node*/\n\twhile (pbuf_list != NULL){\n\t\tpbuf_list = pbuf_list->pnext;\n\t\tpbuf_num ++;\n\t}\n\treturn pbuf_num;\n}\n\n/******************************************************************************\n * FunctionName : espconn_regist_sentcb\n * Description  : Used to specify the function that should be called when data\n *                has been successfully delivered to the remote host.\n * Parameters   : espconn -- espconn to set the sent callback\n *                sent_cb -- sent callback function to call for this espconn\n *                when data is successfully sent\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb)\n{\n    if (espconn == NULL) {\n    \treturn ESPCONN_ARG;\n    }\n\n    espconn ->sent_callback = sent_cb;\n    return ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_regist_sentcb\n * Description  : Used to specify the function that should be called when data\n *                has been successfully delivered to the remote host.\n * Parameters   : espconn -- espconn to set the sent callback\n *                sent_cb -- sent callback function to call for this espconn\n *                when data is successfully sent\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn)\n{\n    if (espconn == NULL || espconn ->proto.tcp == NULL || espconn->type == ESPCONN_UDP) {\n    \treturn ESPCONN_ARG;\n    }\n\n    espconn ->proto.tcp->write_finish_fn = write_finish_fn;\n    return ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_regist_connectcb\n * Description  : used to specify the function that should be called when\n *                connects to host.\n * Parameters   : espconn -- espconn to set the connect callback\n *                connect_cb -- connected callback function to call when connected\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb)\n{\n    if (espconn == NULL) {\n    \treturn ESPCONN_ARG;\n    }\n\n    espconn->proto.tcp->connect_callback = connect_cb;\n    return ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_regist_recvcb\n * Description  : used to specify the function that should be called when recv\n *                data from host.\n * Parameters   : espconn -- espconn to set the recv callback\n *                recv_cb -- recv callback function to call when recv data\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb)\n{\n    if (espconn == NULL) {\n    \treturn ESPCONN_ARG;\n    }\n\n    espconn ->recv_callback = recv_cb;\n    return ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_regist_reconcb\n * Description  : used to specify the function that should be called when connection\n *                because of err disconnect.\n * Parameters   : espconn -- espconn to set the err callback\n *                recon_cb -- err callback function to call when err\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb)\n{\n    if (espconn == NULL) {\n    \treturn ESPCONN_ARG;\n    }\n\n    espconn ->proto.tcp->reconnect_callback = recon_cb;\n    return ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_regist_disconcb\n * Description  : used to specify the function that should be called when disconnect\n * Parameters   : espconn -- espconn to set the err callback\n *                discon_cb -- err callback function to call when err\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb)\n{\n    if (espconn == NULL) {\n    \treturn ESPCONN_ARG;\n    }\n\n    espconn ->proto.tcp->disconnect_callback = discon_cb;\n    return ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_get_connection_info\n * Description  : used to specify the function that should be called when disconnect\n * Parameters   : espconn -- espconn to set the err callback\n *                discon_cb -- err callback function to call when err\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags)\n{\n\tespconn_msg *plist = NULL;\n\n\tif (pespconn == NULL)\n\t\treturn ESPCONN_ARG;\n\n\tos_memset(premot, 0, sizeof(premot));\n\tpespconn->link_cnt = 0;\n\tplist = plink_active;\n\tswitch (pespconn->type){\n\t\tcase ESPCONN_TCP:\n\t\t\twhile(plist != NULL){\n\t\t\t\tif (plist->preverse == pespconn){\n\t\t\t\t\tpremot[pespconn->link_cnt].state = plist->pespconn->state;\n\t\t\t\t\tpremot[pespconn->link_cnt].remote_port = plist->pcommon.remote_port;\n\t\t\t\t\tos_memcpy(premot[pespconn->link_cnt].remote_ip,\tplist->pcommon.remote_ip, 4);\n\t\t\t\t\tpespconn->link_cnt ++;\n\t\t\t\t}\n\t\t\t\tplist = plist->pnext;\n\t\t\t}\n\n\t\t\tbreak;\n\t\tcase ESPCONN_UDP:\n\t\t\twhile(plist != NULL){\n\t\t\t\tif (plist->pespconn && plist->pespconn->type == ESPCONN_UDP){\n\t\t\t\t\tpremot[pespconn->link_cnt].state = plist->pespconn->state;\n\t\t\t\t\tpremot[pespconn->link_cnt].remote_port = plist->pcommon.remote_port;\n\t\t\t\t\tos_memcpy(premot[pespconn->link_cnt].remote_ip, plist->pcommon.remote_ip, 4);\n\t\t\t\t\tpespconn->link_cnt ++;\n\t\t\t\t}\n\t\t\t\tplist = plist->pnext;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\t*pcon_info = premot;\n\treturn ESPCONN_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_accept\n * Description  : The function given as the listen\n * Parameters   : espconn -- the espconn used to listen the connection\n * Returns      :\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_accept(struct espconn *espconn)\n{\n\tsint8 value = ESPCONN_OK;\n\tespconn_msg *plist = NULL;\n\n    if (espconn == NULL) {\n        return ESPCONN_ARG;\n    } else if (espconn ->type != ESPCONN_TCP)\n    \treturn ESPCONN_ARG;\n\n    /*check the active node information whether is the same as the entity or not*/\n    for (plist = plink_active; plist != NULL; plist = plist->pnext){\n    \tif (plist->pespconn && plist->pespconn->type == ESPCONN_TCP){\n    \t\tif (espconn->proto.tcp->local_port == plist->pespconn->proto.tcp->local_port){\n    \t\t\treturn ESPCONN_ISCONN;\n    \t\t}\n    \t}\n    }\n    value = espconn_tcp_server(espconn);\n\n    return value;\n}\n\n/******************************************************************************\n * FunctionName : espconn_regist_time\n * Description  : used to specify the time that should be called when don't recv data\n * Parameters   : espconn -- the espconn used to the connection\n * \t\t\t\t  interval -- the timer when don't recv data\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag)\n{\n\tespconn_msg *pnode = NULL;\n\tespconn_msg *ptime_msg = NULL;\n\tbool value = false;\n\tif ((espconn == NULL) || (type_flag > 0x01))\n\t\treturn ESPCONN_ARG;\n\n\tif (type_flag == 0x01){\n\t\t/*set the timeout time for one active connection of the server*/\n\t\tvalue = espconn_find_connection(espconn, &pnode);\n\t\tif (value){\n\t\t\tpnode->pcommon.timeout = interval;\n\t\t\treturn ESPCONN_OK;\n\t\t} else\n\t\t\treturn ESPCONN_ARG;\n\t} else {\n\t\t/*set the timeout time for all active connection of the server*/\n\t\tptime_msg = pserver_list;\n\t\twhile (ptime_msg != NULL){\n\t\t\tif (ptime_msg->pespconn == espconn){\n\t\t\t\tptime_msg->pcommon.timeout = interval;\n\t\t\t\treturn ESPCONN_OK;\n\t\t\t}\n\t\t\tptime_msg = ptime_msg->pnext;\n\t\t}\n\t}\n\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_disconnect\n * Description  : disconnect with host\n * Parameters   : espconn -- the espconn used to disconnect the connection\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_disconnect(struct espconn *espconn)\n{\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n\n    if (espconn == NULL) {\n        return ESPCONN_ARG;;\n    } else if (espconn ->type != ESPCONN_TCP)\n    \treturn ESPCONN_ARG;\n\n    /*Find the node depend on the espconn message*/\n    value = espconn_find_connection(espconn, &pnode);\n\n    if (value){\n    \t/*protect for redisconnection*/\n    \tif (espconn->state == ESPCONN_CLOSE)\n    \t\treturn ESPCONN_INPROGRESS;\n    \tespconn_tcp_disconnect(pnode);\n    \treturn ESPCONN_OK;\n    } else\n    \treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_get_packet_info\n * Description  : get the packet info with host\n * Parameters   : espconn -- the espconn used to disconnect the connection\n * \t\t\t\t  infoarg -- the packet info\n * Returns      : the errur code\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg)\n{\n\tespconn_msg *pnode = NULL;\n\terr_t err;\n\tbool value = false;\n\n\tif (espconn == NULL || infoarg == NULL) {\n\t\treturn ESPCONN_ARG;;\n\t} else if (espconn->type != ESPCONN_TCP)\n\t\treturn ESPCONN_ARG;\n\n\t/*Find the node depend on the espconn message*/\n\tvalue = espconn_find_connection(espconn, &pnode);\n\tif (value) {\n\t\tstruct tcp_pcb *pcb = pnode->pcommon.pcb;\n\t\tif (pcb == NULL)\n\t\t\treturn ESPCONN_ARG;\n\n\t\tpnode->pcommon.packet_info.packseq_nxt = pcb->rcv_nxt;\n\t\tpnode->pcommon.packet_info.packseqno = pcb->snd_nxt;\n\t\tpnode->pcommon.packet_info.snd_buf_size = pcb->snd_buf;\n\t\tpnode->pcommon.packet_info.total_queuelen = TCP_SND_QUEUELEN;\n\t\tpnode->pcommon.packet_info.snd_queuelen = pnode->pcommon.packet_info.total_queuelen - pcb->snd_queuelen;\n\t\tos_memcpy(infoarg,(void*)&pnode->pcommon.packet_info, sizeof(struct espconn_packet));\n\t\treturn ESPCONN_OK;\n\t} else {\n\t\tswitch (espconn->state){\n\t\t\tcase ESPCONN_CLOSE:\n\t\t\t\tos_memcpy(infoarg,(void*)&pktinfo[0], sizeof(struct espconn_packet));\n\t\t\t\terr = ESPCONN_OK;\n\t\t\t\tbreak;\n\t\t\tcase ESPCONN_NONE:\n\t\t\t\tos_memcpy(infoarg,(void*)&pktinfo[1], sizeof(struct espconn_packet));\n\t\t\t\terr = ESPCONN_OK;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\terr = ESPCONN_ARG;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn err;\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_set_opt\n * Description  : set the option for connections so that we don't end up bouncing\n *                all connections at the same time .\n * Parameters   : espconn -- the espconn used to set the connection\n * \t\t\t\t  opt -- the option for set\n * Returns      : the result\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_set_opt(struct espconn *espconn, uint8 opt)\n{\n\tespconn_msg *pnode = NULL;\n\tstruct tcp_pcb *tpcb;\n\tbool value = false;\n\n\tif (espconn == NULL) {\n\t\treturn ESPCONN_ARG;;\n\t} else if (espconn->type != ESPCONN_TCP)\n\t\treturn ESPCONN_ARG;\n\n\t/*Find the node depend on the espconn message*/\n\tvalue = espconn_find_connection(espconn, &pnode);\n\tif (value) {\n\t\tpnode->pcommon.espconn_opt |= opt;\n\t\ttpcb = pnode->pcommon.pcb;\n\t\tif (espconn_delay_disabled(pnode))\n\t\t\ttcp_nagle_disable(tpcb);\n\n\t\tif (espconn_keepalive_disabled(pnode))\n\t\t\tespconn_keepalive_enable(tpcb);\n\n\t\treturn ESPCONN_OK;\n\t} else\n\t\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_clear_opt\n * Description  : clear the option for connections so that we don't end up bouncing\n *                all connections at the same time .\n * Parameters   : espconn -- the espconn used to set the connection\n * \t\t\t\t  opt -- the option for clear\n * Returns      : the result\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_clear_opt(struct espconn *espconn, uint8 opt)\n{\n\tespconn_msg *pnode = NULL;\n\tstruct tcp_pcb *tpcb;\n\tbool value = false;\n\n\tif (espconn == NULL) {\n\t\treturn ESPCONN_ARG;;\n\t} else if (espconn->type != ESPCONN_TCP)\n\t\treturn ESPCONN_ARG;\n\n\t/*Find the node depend on the espconn message*/\n\tvalue = espconn_find_connection(espconn, &pnode);\n\tif (value) {\n\t\tpnode->pcommon.espconn_opt &= ~opt;\n\t\ttpcb = pnode->pcommon.pcb;\n\t\tif (espconn_keepalive_enabled(pnode))\n\t\t\tespconn_keepalive_disable(tpcb);\n\n\t\tif (espconn_delay_enabled(pnode))\n\t\t\ttcp_nagle_enable(tpcb);\n\n\t\treturn ESPCONN_OK;\n\t} else\n\t\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_set_keepalive\n * Description  : access level value for connection so that we set the value for\n * \t\t\t\t  keep alive\n * Parameters   : espconn -- the espconn used to set the connection\n * \t\t\t\t  level -- the connection's level\n * \t\t\t\t  value -- the value of time(s)\n * Returns      : access port value\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg)\n{\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n\tsint8 ret = ESPCONN_OK;\n\n\tif (espconn == NULL || optarg == NULL) {\n\t\treturn ESPCONN_ARG;;\n\t} else if (espconn->type != ESPCONN_TCP)\n\t\treturn ESPCONN_ARG;\n\n\t/*Find the node depend on the espconn message*/\n\tvalue = espconn_find_connection(espconn, &pnode);\n\tif (value && espconn_keepalive_disabled(pnode)) {\n\t\tstruct tcp_pcb *pcb = pnode->pcommon.pcb;\n\t\tswitch (level){\n\t\t\tcase ESPCONN_KEEPIDLE:\n\t\t\t\tpcb->keep_idle = 1000 * (u32_t)(*(int*)optarg);\n\t\t\t\tret = ESPCONN_OK;\n\t\t\t\tbreak;\n\t\t\tcase ESPCONN_KEEPINTVL:\n\t\t\t\tpcb->keep_intvl = 1000 * (u32_t)(*(int*)optarg);\n\t\t\t\tret = ESPCONN_OK;\n\t\t\t\tbreak;\n\t\t\tcase ESPCONN_KEEPCNT:\n\t\t\t\tpcb->keep_cnt = (u32_t)(*(int*)optarg);\n\t\t\t\tret = ESPCONN_OK;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tret = ESPCONN_ARG;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn ret;\n\t} else\n\t\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_get_keepalive\n * Description  : access level value for connection so that we get the value for\n * \t\t\t\t  keep alive\n * Parameters   : espconn -- the espconn used to get the connection\n * \t\t\t\t  level -- the connection's level\n * Returns      : access keep alive value\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg)\n{\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n\tsint8 ret = ESPCONN_OK;\n\n\tif (espconn == NULL || optarg == NULL) {\n\t\treturn ESPCONN_ARG;;\n\t} else if (espconn->type != ESPCONN_TCP)\n\t\treturn ESPCONN_ARG;\n\n\t/*Find the node depend on the espconn message*/\n\tvalue = espconn_find_connection(espconn, &pnode);\n\tif (value && espconn_keepalive_disabled(pnode)) {\n\t\tstruct tcp_pcb *pcb = pnode->pcommon.pcb;\n\t\tswitch (level) {\n\t\tcase ESPCONN_KEEPIDLE:\n\t\t\t*(int*)optarg = (int)(pcb->keep_idle/1000);\n\t\t\tret = ESPCONN_OK;\n\t\t\tbreak;\n\t\tcase ESPCONN_KEEPINTVL:\n\t\t\t*(int*)optarg = (int)(pcb->keep_intvl/1000);\n\t\t\tret = ESPCONN_OK;\n\t\t\tbreak;\n\t\tcase ESPCONN_KEEPCNT:\n\t\t\t*(int*)optarg = (int)(pcb->keep_cnt);\n\t\t\tret = ESPCONN_OK;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tret = ESPCONN_ARG;\n\t\t\tbreak;\n\t\t}\n\t\treturn ret;\n\t} else\n\t\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_delete\n * Description  : disconnect with host\n * Parameters   : espconn -- the espconn used to disconnect the connection\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_delete(struct espconn *espconn)\n{\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n\n    if (espconn == NULL) {\n        return ESPCONN_ARG;\n    } else if (espconn ->type != ESPCONN_UDP)\n    \treturn espconn_tcp_delete(espconn);\n\n    /*Find the node depend on the espconn message*/\n    value = espconn_find_connection(espconn, &pnode);\n\n    if (value){\n    \tespconn_udp_disconnect(pnode);\n    \treturn ESPCONN_OK;\n    } else\n    \treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_port\n * Description  : access port value for client so that we don't end up bouncing\n *                all connections at the same time .\n * Parameters   : none\n * Returns      : access port value\n*******************************************************************************/\nuint32 ICACHE_FLASH_ATTR\nespconn_port(void)\n{\n    uint32 port = 0;\n    static uint32 randnum = 0;\n\n    do {\n        port = system_get_time();\n\n        if (port < 0) {\n            port = os_random() - port;\n        }\n\n        port %= 0xc350;\n\n        if (port < 0x400) {\n            port += 0x400;\n        }\n\n    } while (port == randnum);\n\n    randnum = port;\n\n    return port;\n}\n\n/******************************************************************************\n * FunctionName : espconn_gethostbyname\n * Description  : Resolve a hostname (string) into an IP address.\n * Parameters   : pespconn -- espconn to resolve a hostname\n *                hostname -- the hostname that is to be queried\n *                addr -- pointer to a ip_addr_t where to store the address if \n *                        it is already cached in the dns_table (only valid if\n *                        ESPCONN_OK is returned!)\n *                found -- a callback function to be called on success, failure\n *                         or timeout (only if ERR_INPROGRESS is returned!)\n * Returns      : err_t return code\n *                - ESPCONN_OK if hostname is a valid IP address string or the host\n *                  name is already in the local names table.\n *                - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server\n *                  for resolution if no errors are present.\n *                - ESPCONN_ARG: dns client not initialized or invalid hostname\n*******************************************************************************/\nerr_t ICACHE_FLASH_ATTR\nespconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found)\n{\n    return dns_gethostbyname(hostname, addr, found, pespconn);\n}\n\n/******************************************************************************\n * FunctionName : espconn_dns_setserver\n * Description  : Initialize one of the DNS servers.\n * Parameters   : numdns -- the index of the DNS server to set must\n * \t\t\t\t  be < DNS_MAX_SERVERS = 2\n * \t\t\t      dnsserver -- IP address of the DNS server to set\n *  Returns     : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_dns_setserver(u8_t numdns, ip_addr_t *dnsserver)\n{\n\tdns_setserver(numdns,dnsserver);\n}\n\n"
  },
  {
    "path": "app/lwip/app/espconn_mdns.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: espconn_mdns.c\n *\n * Description: udp proto interface\n *\n * Modification history:\n *     2014/3/31, v1.0 create this file.\n*******************************************************************************/\n\n#include \"ets_sys.h\"\n#include \"os_type.h\"\n\n#include \"lwip/mdns.h\"\n\n/******************************************************************************\n * FunctionName : espconn_mdns_enable\n * Description  : join a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_mdns_enable(void)\n{\n\tmdns_enable();\n}\n/******************************************************************************\n * FunctionName : espconn_mdns_disable\n * Description  : join a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_mdns_disable(void)\n{\n\tmdns_disable();\n}\n\n/******************************************************************************\n * FunctionName : espconn_mdns_set_hostname\n * Description  : join a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_mdns_set_hostname(char *name)\n{\n\tmdns_set_hostname(name);\n}\n\n/******************************************************************************\n * FunctionName : espconn_mdns_init\n * Description  : join a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nchar* ICACHE_FLASH_ATTR\nespconn_mdns_get_hostname(void)\n{\n\treturn (char *)mdns_get_hostname();\n}\n/******************************************************************************\n * FunctionName : espconn_mdns_get_servername\n * Description  : join a multicast group\n * Parameters   : info -- the info  of mdns\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_mdns_set_servername(const char *name)\n{\n\tmdns_set_servername(name);\n}\n/******************************************************************************\n * FunctionName : espconn_mdns_get_servername\n * Description  : join a multicast group\n * Parameters   : info -- the info  of mdns\n * Returns      : none\n*******************************************************************************/\nchar* ICACHE_FLASH_ATTR\nespconn_mdns_get_servername(void)\n{\n\treturn (char *)mdns_get_servername();\n}\n/******************************************************************************\n * FunctionName : mdns_server_register\n * Description  : join a multicast group\n * Parameters   : info -- the info  of mdns\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_mdns_server_register(void)\n{\n\tmdns_server_register();\n}\n/******************************************************************************\n * FunctionName : mdns_server_register\n * Description  : join a multicast group\n * Parameters   : info -- the info  of mdns\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_mdns_server_unregister(void)\n{\n\tmdns_server_unregister();\n}\n/******************************************************************************\n * FunctionName : espconn_mdns_init\n * Description  : join a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_mdns_close(void)\n{\n\tmdns_close();\n}\n/******************************************************************************\n * FunctionName : espconn_mdns_init\n * Description  : join a multicast group\n * Parameters   : host_ip -- the ip address of udp server\n * \t\t\t\t  multicast_ip -- multicast ip given by user\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_mdns_init(struct mdns_info *info)\n{\n\tmdns_init(info);\n}\n"
  },
  {
    "path": "app/lwip/app/espconn_tcp.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: espconn_tcp.c\n *\n * Description: tcp proto interface\n *\n * Modification history:\n *     2014/3/31, v1.0 create this file.\n*******************************************************************************/\n\n#include \"lwip/netif.h\"\n#include \"lwip/inet.h\"\n#include \"netif/etharp.h\"\n#include \"lwip/tcp.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/init.h\"\n#include \"lwip/tcp_impl.h\"\n#include \"lwip/memp.h\"\n\n#include \"ets_sys.h\"\n#include \"os_type.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/app/espconn_tcp.h\"\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\nextern espconn_msg *plink_active;\nextern espconn_msg *pserver_list;\nextern struct espconn_packet pktinfo[2];\nextern struct tcp_pcb ** const tcp_pcb_lists[];\n\nos_event_t espconn_TaskQueue[espconn_TaskQueueLen];\n\nstatic err_t\nespconn_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);\nstatic void\nespconn_client_close(void *arg, struct tcp_pcb *pcb);\n\nstatic err_t\nespconn_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);\nstatic void\nespconn_server_close(void *arg, struct tcp_pcb *pcb);\n\n///////////////////////////////common function/////////////////////////////////\n/******************************************************************************\n * FunctionName : espconn_kill_oldest\n * Description  : kill the oldest TCP block\n * Parameters   : none\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_kill_oldest(void)\n{\n\tstruct tcp_pcb *pcb, *inactive;\n\tu32_t inactivity;\n\n\tinactivity = 0;\n\tinactive = NULL;\n\t/* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */\n\tfor (pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\n\t\tif ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) {\n\t\t\tinactivity = tcp_ticks - pcb->tmr;\n\t\t\tinactive = pcb;\n\t\t}\n\t}\n\tif (inactive != NULL) {\n\t\ttcp_abort(inactive);\n\t}\n\n\t/* Go through the list of FIN_WAIT_2 pcbs and get the oldest pcb. */\n\tinactivity = 0;\n\tinactive = NULL;\n\tfor (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\n\t\tif (pcb->state == FIN_WAIT_1 || pcb->state == FIN_WAIT_2){\n\t\t\tif ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) {\n\t\t\t\tinactivity = tcp_ticks - pcb->tmr;\n\t\t\t\tinactive = pcb;\n\t\t\t}\n\t\t}\n\t}\n\t/*Purges the PCB, removes it from a PCB list and frees the memory*/\n\tif (inactive != NULL) {\n\t\ttcp_pcb_remove(&tcp_active_pcbs, inactive);\n\t\tmemp_free(MEMP_TCP_PCB, inactive);\n\t}\n\n\t/* Go through the list of LAST_ACK pcbs and get the oldest pcb. */\n\tinactivity = 0;\n\tinactive = NULL;\n\tfor (pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\n\t\tif (pcb->state == LAST_ACK) {\n\t\t\tif ((u32_t) (tcp_ticks - pcb->tmr) >= inactivity) {\n\t\t\t\tinactivity = tcp_ticks - pcb->tmr;\n\t\t\t\tinactive = pcb;\n\t\t\t}\n\t\t}\n\t}\n\t/*Purges the PCB, removes it from a PCB list and frees the memory*/\n\tif (inactive != NULL) {\n\t\ttcp_pcb_remove(&tcp_active_pcbs, inactive);\n\t\tmemp_free(MEMP_TCP_PCB, inactive);\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_kill_oldest_pcb\n * Description  : find the oldest TCP block by state\n * Parameters   : none\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_kill_oldest_pcb(void)\n{\n\tstruct tcp_pcb *cpcb = NULL;\n\tuint8 i = 0;\n\tuint8 num_tcp_fin = 0;\n\tfor(i = 2; i < 4; i ++){\n\t\tfor (cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {\n\t\t\tif (cpcb->state == TIME_WAIT){\n\t\t\t\tnum_tcp_fin ++;\n\t\t\t\tif (num_tcp_fin == MEMP_NUM_TCP_PCB)\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (cpcb->state == FIN_WAIT_1 || cpcb->state == FIN_WAIT_2 || cpcb->state == LAST_ACK){\n\t\t\t\tnum_tcp_fin++;\n\t\t\t\tif (num_tcp_fin == MEMP_NUM_TCP_PCB)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (num_tcp_fin == MEMP_NUM_TCP_PCB){\n\t\t\tnum_tcp_fin = 0;\n\t\t\tespconn_kill_oldest();\n\t\t} else if (cpcb == NULL){\n\t\t\tnum_tcp_fin = 0;\n\t\t}\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_kill_pcb\n * Description  : kill all the TCP block by port\n * Parameters   : none\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_kill_pcb(u16_t port)\n{\n\tstruct tcp_pcb *cpcb = NULL;\n\tuint8 i = 0;\n\tstruct tcp_pcb *inactive = NULL;\n\tstruct tcp_pcb *prev = NULL;\n\tu8_t pcb_remove;\n\t/* Check if the address already is in use (on all lists) */\n\tfor (i = 1; i < 4; i++) {\n\t\tcpcb = *tcp_pcb_lists[i];\n\t\twhile(cpcb != NULL){\n\t\t\tpcb_remove = 0;\n\t\t\tif (cpcb->local_port == port) {\n\t\t\t\t++pcb_remove;\n\t\t\t}\n\t\t\t/* If the PCB should be removed, do it. */\n\t\t\tif (pcb_remove) {\n\t\t\t\t/* Remove PCB from tcp_pcb_lists list. */\n\t\t\t\tinactive = cpcb;\n\t\t\t\tcpcb = inactive->next;\n\t\t\t\ttcp_pcb_remove(tcp_pcb_lists[i], inactive);\n\t\t\t\tmemp_free(MEMP_TCP_PCB, inactive);\n\t\t\t} else {\n\t\t\t\tcpcb = cpcb->next;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_find_current_pcb\n * Description  : find the TCP block which option\n * Parameters   : pcurrent_msg -- the node in the list which active\n * Returns      : TCP block point\n*******************************************************************************/\nstruct tcp_pcb *ICACHE_FLASH_ATTR espconn_find_current_pcb(espconn_msg *pcurrent_msg)\n{\n\tuint16 local_port = pcurrent_msg->pcommon.local_port;\n\tuint32 local_ip = pcurrent_msg->pcommon.local_ip;\n\tuint16 remote_port = pcurrent_msg->pcommon.remote_port;\n\tuint32 remote_ip = *((uint32*)&pcurrent_msg->pcommon.remote_ip);\n\tstruct tcp_pcb *find_pcb = NULL;\n\tif (pcurrent_msg ->preverse == NULL){/*Find the server's TCP block*/\n\t\tif (local_ip == 0|| local_port == 0) return pcurrent_msg->pcommon.pcb;\n\n\t\tfor (find_pcb = tcp_active_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){\n\t\t\tif ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip) &&\n\t\t\t\t(find_pcb->local_port == local_port) && (find_pcb->local_ip.addr == local_ip))\n\t\t\t\treturn find_pcb;\n\t\t}\n\n\t\tfor (find_pcb = tcp_tw_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){\n\t\t\tif ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip) &&\n\t\t\t\t(find_pcb->local_port == local_port) && (find_pcb->local_ip.addr == local_ip))\n\t\t\t\treturn find_pcb;\n\t\t}\n\t} else {/*Find the client's TCP block*/\n\t\tif (remote_ip == 0|| remote_port == 0) return pcurrent_msg->pcommon.pcb;\n\n\t\tfor (find_pcb = tcp_active_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){\n\t\t\tif ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip))\n\t\t\t\treturn find_pcb;\n\t\t}\n\n\t\tfor (find_pcb = tcp_tw_pcbs; find_pcb != NULL; find_pcb = find_pcb->next){\n\t\t\tif ((find_pcb->remote_port == remote_port) && (find_pcb->remote_ip.addr == remote_ip))\n\t\t\t\treturn find_pcb;\n\t\t}\n\t}\n\treturn NULL;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_reconnect\n * Description  : reconnect with host\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_tcp_reconnect(void *arg)\n{\n\tespconn_msg *precon_cb = arg;\n\tsint8 re_err = 0;\n\tespconn_buf *perr_buf = NULL;\n\tespconn_buf *perr_back = NULL;\n\tespconn_kill_oldest_pcb();\n\tif (precon_cb != NULL) {\n\t\tstruct espconn *espconn = precon_cb->preverse;\n\t\tre_err = precon_cb->pcommon.err;\n\t\tif (precon_cb->pespconn != NULL){\n\t\t\tif (espconn != NULL){/*Process the server's message block*/\n\t\t\t\tif (precon_cb->pespconn->proto.tcp != NULL){\n\t\t\t\t\tespconn_copy_partial(espconn, precon_cb->pespconn);\n\t\t\t\t\tespconn_printf(\"server: %d.%d.%d.%d : %d reconnection\\n\", espconn->proto.tcp->remote_ip[0],\n\t\t\t\t\t\t\tespconn->proto.tcp->remote_ip[1],espconn->proto.tcp->remote_ip[2],\n\t\t\t\t\t\t\tespconn->proto.tcp->remote_ip[3],espconn->proto.tcp->remote_port);\n\t\t\t\t\tos_free(precon_cb->pespconn->proto.tcp);\n\t\t\t\t\tprecon_cb->pespconn->proto.tcp = NULL;\n\t\t\t\t}\n\t\t\t\tos_free(precon_cb->pespconn);\n\t\t\t\tprecon_cb->pespconn = NULL;\n\t\t\t} else {/*Process the client's message block*/\n\t\t\t\tespconn = precon_cb->pespconn;\n\t\t\t\tespconn_printf(\"client: %d.%d.%d.%d : %d reconnection\\n\", espconn->proto.tcp->local_ip[0],\n\t\t\t\t\t\t\t\t\t\tespconn->proto.tcp->local_ip[1],espconn->proto.tcp->local_ip[2],\n\t\t\t\t\t\t\t\t\t\tespconn->proto.tcp->local_ip[3],espconn->proto.tcp->local_port);\n\t\t\t}\n\t\t}\n\n\t\t/*to prevent memory leaks, ensure that each allocated is deleted*/\n\t\tperr_buf = precon_cb->pcommon.pbuf;\n\t\twhile (perr_buf != NULL){\n\t\t\tperr_back = perr_buf;\n\t\t\tperr_buf = perr_back->pnext;\n\t\t\tespconn_pbuf_delete(&precon_cb->pcommon.pbuf,perr_back);\n\t\t\tos_free(perr_back);\n\t\t\tperr_back = NULL;\n\t\t}\n\t\tos_bzero(&pktinfo[1], sizeof(struct espconn_packet));\n\t\tos_memcpy(&pktinfo[1], (void*)&precon_cb->pcommon.packet_info, sizeof(struct espconn_packet));\n\t\tos_free(precon_cb);\n\t\tprecon_cb = NULL;\n\t\tif (espconn && espconn->proto.tcp && espconn->proto.tcp->reconnect_callback != NULL) {\n\t\t\tespconn->proto.tcp->reconnect_callback(espconn, re_err);\n\t\t}\n\t} else {\n\t\tespconn_printf(\"espconn_tcp_reconnect err\\n\");\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_disconnect\n * Description  : disconnect with host\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_tcp_disconnect_successful(void *arg)\n{\n\tespconn_msg *pdiscon_cb = arg;\n\tsint8 dis_err = 0;\n\tespconn_buf *pdis_buf = NULL;\n\tespconn_buf *pdis_back = NULL;\n\tespconn_kill_oldest_pcb();\n\tif (pdiscon_cb != NULL) {\n\t\tstruct espconn *espconn = pdiscon_cb->preverse;\n\n\t\tdis_err = pdiscon_cb->pcommon.err;\n\t\tif (pdiscon_cb->pespconn != NULL){\n\t\t\tstruct tcp_pcb *pcb = NULL;\n\t\t\tif (espconn != NULL){/*Process the server's message block*/\n\t\t\t\tif (pdiscon_cb->pespconn->proto.tcp != NULL && espconn->proto.tcp){\n\t\t\t\t\tespconn_copy_partial(espconn, pdiscon_cb->pespconn);\n\t\t\t\t\tespconn_printf(\"server: %d.%d.%d.%d : %d disconnect\\n\", espconn->proto.tcp->remote_ip[0],\n\t\t\t\t\t\t\tespconn->proto.tcp->remote_ip[1],espconn->proto.tcp->remote_ip[2],\n\t\t\t\t\t\t\tespconn->proto.tcp->remote_ip[3],espconn->proto.tcp->remote_port);\n\t\t\t\t\tos_free(pdiscon_cb->pespconn->proto.tcp);\n\t\t\t\t\tpdiscon_cb->pespconn->proto.tcp = NULL;\n\t\t\t\t}\n\t\t\t\tos_free(pdiscon_cb->pespconn);\n\t\t\t\tpdiscon_cb->pespconn = NULL;\n\t\t\t} else {/*Process the client's message block*/\n\t\t\t\tespconn = pdiscon_cb->pespconn;\n\t\t\t\tespconn_printf(\"client: %d.%d.%d.%d : %d disconnect\\n\", espconn->proto.tcp->local_ip[0],\n\t\t\t\t\t\tespconn->proto.tcp->local_ip[1],espconn->proto.tcp->local_ip[2],\n\t\t\t\t\t\tespconn->proto.tcp->local_ip[3],espconn->proto.tcp->local_port);\n\t\t\t}\n\t\t\t/*process the current TCP block*/\n\t\t\tpcb = espconn_find_current_pcb(pdiscon_cb);\n\t\t\tif (pcb != NULL){\n\t\t\t\tif (espconn_reuse_disabled(pdiscon_cb)) {\n\t\t\t\t\tstruct tcp_pcb *cpcb = NULL;\n\t\t\t\t\tstruct tcp_pcb *prev = NULL;\n\t\t\t\t\tu8_t pcb_remove;\n\t\t\t\t\tespconn_printf(\"espconn_tcp_disconnect_successful %d, %d\\n\",\tpcb->state, pcb->local_port);\n\t\t\t\t\tcpcb = tcp_tw_pcbs;\n\t\t\t\t\twhile (cpcb != NULL) {\n\t\t\t\t\t\tpcb_remove = 0;\n\t\t\t\t\t\tif (cpcb->local_port == pcb->local_port) {\n\t\t\t\t\t\t\t++pcb_remove;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* If the PCB should be removed, do it. */\n\t\t\t\t\t\tif (pcb_remove) {\n\t\t\t\t\t\t\tstruct tcp_pcb *backup_pcb = NULL;\n\t\t\t\t\t\t\ttcp_pcb_purge(cpcb);\n\t\t\t\t\t\t\t/* Remove PCB from tcp_tw_pcbs list. */\n\t\t\t\t\t\t\tif (prev != NULL) {\n\t\t\t\t\t\t\t\tLWIP_ASSERT(\"espconn_tcp_delete: middle cpcb != tcp_tw_pcbs\",cpcb != tcp_tw_pcbs);\n\t\t\t\t\t\t\t\tprev->next = cpcb->next;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t/* This PCB was the first. */\n\t\t\t\t\t\t\t\tLWIP_ASSERT(\"espconn_tcp_delete: first cpcb == tcp_tw_pcbs\",tcp_tw_pcbs == cpcb);\n\t\t\t\t\t\t\t\ttcp_tw_pcbs = cpcb->next;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbackup_pcb = cpcb;\n\t\t\t\t\t\t\tcpcb = cpcb->next;\n\t\t\t\t\t\t\tmemp_free(MEMP_TCP_PCB, backup_pcb);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tprev = cpcb;\n\t\t\t\t\t\t\tcpcb = cpcb->next;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\ttcp_arg(pcb, NULL);\n\t\t\t\t\ttcp_err(pcb, NULL);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/*to prevent memory leaks, ensure that each allocated is deleted*/\n\t\tpdis_buf = pdiscon_cb->pcommon.pbuf;\n\t\twhile (pdis_buf != NULL) {\n\t\t\tpdis_back = pdis_buf;\n\t\t\tpdis_buf = pdis_back->pnext;\n\t\t\tespconn_pbuf_delete(&pdiscon_cb->pcommon.pbuf, pdis_back);\n\t\t\tos_free(pdis_back);\n\t\t\tpdis_back = NULL;\n\t\t}\n\t\tos_bzero(&pktinfo[0], sizeof(struct espconn_packet));\n\t\tos_memcpy(&pktinfo[0], (void*)&pdiscon_cb->pcommon.packet_info, sizeof(struct espconn_packet));\n\t\tos_free(pdiscon_cb);\n\t\tpdiscon_cb = NULL;\n\t\tif (espconn->proto.tcp && espconn->proto.tcp->disconnect_callback != NULL) {\n\t\t\tespconn->proto.tcp->disconnect_callback(espconn);\n\t\t}\n\t} else {\n\t\tespconn_printf(\"espconn_tcp_disconnect err\\n\");\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_Task\n * Description  : espconn processing task\n * Parameters   : events -- contain the espconn processing data\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_Task(os_event_t *events)\n{\n\tespconn_msg *task_msg = NULL;\n\tstruct espconn *pespconn = NULL;\n\n\ttask_msg = (espconn_msg *) events->par;\n\tswitch (events->sig) {\n\t\tcase SIG_ESPCONN_WRITE: {\n\t\t\tpespconn = task_msg->pespconn;\n\t\t\tif (pespconn == NULL) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (pespconn->proto.tcp->write_finish_fn != NULL) {\n\t\t\t\tpespconn->proto.tcp->write_finish_fn(pespconn);\n\t\t\t}\n\t\t}\n\t\t\tbreak;\n\t\tcase SIG_ESPCONN_ERRER:\n\t\t\t/*remove the node from the client's active connection list*/\n\t\t\tespconn_list_delete(&plink_active, task_msg);\n\t\t\tespconn_tcp_reconnect(task_msg);\n\t\t\tbreak;\n\t\tcase SIG_ESPCONN_CLOSE:\n\t\t\t/*remove the node from the client's active connection list*/\n\t\t\tespconn_list_delete(&plink_active, task_msg);\n\t\t\tespconn_tcp_disconnect_successful(task_msg);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_sent\n * Description  : sent data for client or server\n * Parameters   : void *arg -- client or server to send\n *                uint8* psent -- Data to send\n *                uint16 length -- Length of data to send\n * Returns      : return espconn error code.\n * - ESPCONN_OK. Successful. No error occured.\n * - ESPCONN_MEM. Out of memory.\n * - ESPCONN_RTE. Could not find route to destination address.\n * - More errors could be returned by lower protocol layers.\n*******************************************************************************/\nerr_t ICACHE_FLASH_ATTR\nespconn_tcp_sent(void *arg, uint8 *psent, uint16 length)\n{\n\tespconn_msg *ptcp_sent = arg;\n    struct tcp_pcb *pcb = NULL;\n    err_t err = 0;\n    u16_t len = 0;\n    u8_t data_to_send = false;\n\n    espconn_printf(\"espconn_tcp_sent ptcp_sent %p psent %p length %d\\n\", ptcp_sent, psent, length);\n\n    /*Check the parameters*/\n    if (ptcp_sent == NULL || psent == NULL || length == 0) {\n        return ESPCONN_ARG;\n    }\n\n    /*Set the packet length depend on the sender buffer space*/\n    pcb = ptcp_sent->pcommon.pcb;\n    if (tcp_sndbuf(pcb) < length) {\n        len = tcp_sndbuf(pcb);\n    } else {\n        len = length;\n        LWIP_ASSERT(\"length did not fit into uint16!\", (len == length));\n    }\n\n    if (len > (2*pcb->mss)) {\n        len = 2*pcb->mss;\n    }\n\n    /*Write data for sending, but does not send it immediately*/\n\tdo {\n\t\tespconn_printf(\"espconn_tcp_sent writing %d bytes %p\\n\", len, pcb);\n\t\tif (espconn_copy_disabled(ptcp_sent))\n\t\t\terr = tcp_write(pcb, psent, len, 1);\n\t\telse\n\t\t\terr = tcp_write(pcb, psent, len, 0);\n\n        if (err == ERR_MEM) {\n            len /= 2;\n        }\n    } while (err == ERR_MEM && len > 1);\n\n\t/*Find out what we can send and send it, offset the buffer point for next send*/\n    if (err == ERR_OK) {\n    \tptcp_sent->pcommon.ptail->punsent = psent + len;\n\t\tptcp_sent->pcommon.ptail->unsent = length - len;\n\t\terr = tcp_output(pcb);\n\t\t/*If enable the copy option, change the flag for next write*/\n\t\tif (espconn_copy_disabled(ptcp_sent)){\n\t\t\tif (ptcp_sent->pcommon.ptail->unsent == 0) {\n\t\t\t\tptcp_sent->pcommon.write_flag = true;\n\t\t\t\tets_post(espconn_TaskPrio, SIG_ESPCONN_WRITE, (uint32_t)ptcp_sent);\n\t\t\t}\n\t\t}\n        espconn_printf(\"espconn_tcp_sent %d\\n\", err);\n    }\n    return err;\n}\n\n/******************************************************************************\n * FunctionName : espconn_close\n * Description  : The connection has been successfully closed.\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_tcp_disconnect(espconn_msg *pdiscon)\n{\n\tif (pdiscon != NULL){\n\t\t/*disconnect with the host by send the FIN frame*/\n\t\tif (pdiscon->preverse != NULL)\n\t\t\tespconn_server_close(pdiscon, pdiscon->pcommon.pcb);\n\t\telse\n\t\t\tespconn_client_close(pdiscon, pdiscon->pcommon.pcb);\n\t} else{\n\t\tespconn_printf(\"espconn_tcp_disconnect err.\\n\");\n\t}\n}\n\n///////////////////////////////client function/////////////////////////////////\n/******************************************************************************\n * FunctionName : espconn_client_close\n * Description  : The connection shall be actively closed.\n * Parameters   : pcb -- Additional argument to pass to the callback function\n *                pcb -- the pcb to close\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_client_close(void *arg, struct tcp_pcb *pcb)\n{\n    err_t err;\n    espconn_msg *pclose = arg;\n\n\tpclose->pcommon.pcb = pcb;\n\t/*avoid recalling the disconnect function*/\n\ttcp_recv(pcb, NULL);\n\terr = tcp_close(pcb);\n\n\tif (err != ERR_OK) {\n\t\t/* closing failed, try again later */\n\t\ttcp_recv(pcb, espconn_client_recv);\n\t} else {\n\t\t/* closing succeeded */\n\t\ttcp_sent(pcb, NULL);\n\t\ttcp_err(pcb, NULL);\n\t\t/*switch the state of espconn for application process*/\n\t\tpclose->pespconn->state = ESPCONN_CLOSE;\n\t\tets_post(espconn_TaskPrio, SIG_ESPCONN_CLOSE, (uint32_t)pclose);\n\t}\n}\n\n//***********Code for WIFI_BLOCK from upper**************\nsint8 ICACHE_FLASH_ATTR\nespconn_recv_hold(struct espconn *pespconn)\n{\n\t//1st, according to espconn code, have to find out the escpconn_msg by pespconn;\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n    if (pespconn == NULL) {\n        return ESPCONN_ARG;\n    }\n    value = espconn_find_connection(pespconn, &pnode);\n\tif(value != true)\n\t{\n\t\tos_printf(\"RecvHold, By pespconn,find conn_msg fail\\n\");\n\t\treturn ESPCONN_ARG;\n\t}\n\n\t//2nd, the actual operation\n\tif(pnode->recv_hold_flag == 0)\n\t{\n\t\tpnode->recv_hold_flag = 1;\n\t\tpnode->recv_holded_buf_Len = 0;\n\t}\n\treturn ESPCONN_OK;\n}\n\nsint8 ICACHE_FLASH_ATTR\nespconn_recv_unhold(struct espconn *pespconn)\n{\n\t//1st, according to espconn code, have to find out the escpconn_msg by pespconn;\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n    if (pespconn == NULL) {\n        return ESPCONN_ARG;\n    }\n    value = espconn_find_connection(pespconn, &pnode);\n\tif(value != true)\n\t{\n\t\tos_printf(\"RecvHold, By pespconn,find conn_msg fail\\n\");\n\t\treturn ESPCONN_ARG;\n\t}\n\n\t//2nd, the actual operation\n\tif(pnode->recv_hold_flag == 1)\n\t{\n\t\tif(pespconn->type == ESPCONN_TCP) {\n\t\t\ttcp_recved(pnode->pcommon.pcb, pnode->recv_holded_buf_Len);\n\t\t}\n\t\tpnode->recv_holded_buf_Len = 0;\n\t\tpnode->recv_hold_flag = 0;\n\t}\n\treturn ESPCONN_OK;\n}\n\n//***********Code for WIFI_BLOCK from upper**************\n\n/******************************************************************************\n * FunctionName : espconn_client_recv\n * Description  : Data has been received on this pcb.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb which received data\n *                p -- The received data (or NULL when the connection has been closed!)\n *                err -- An error code if there has been an error receiving\n * Returns      : ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_client_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\n{\n\tespconn_msg *precv_cb = arg;\n\n\ttcp_arg(pcb, arg);\n\n    if (p != NULL) {\n    \t/*To update and advertise a larger window*/\n\t\tif(precv_cb->recv_hold_flag == 0)\n        \ttcp_recved(pcb, p->tot_len);\n\t\telse\n\t\t\tprecv_cb->recv_holded_buf_Len += p->tot_len;\n    }\n\n    if (err == ERR_OK && p != NULL) {\n    \tchar *pdata = NULL;\n    \tu16_t length = 0;\n    \t/*Copy the contents of a packet buffer to an application buffer.\n    \t *to prevent memory leaks, ensure that each allocated is deleted*/\n        pdata = (char *)os_zalloc(p ->tot_len + 1);\n        length = pbuf_copy_partial(p, pdata, p ->tot_len, 0);\n        pbuf_free(p);\n\n        if (length != 0) {\n        \t/*switch the state of espconn for application process*/\n        \tprecv_cb->pespconn ->state = ESPCONN_READ;\n        \tprecv_cb->pcommon.pcb = pcb;\n            if (precv_cb->pespconn->recv_callback != NULL) {\n            \tprecv_cb->pespconn->recv_callback(precv_cb->pespconn, pdata, length);\n            }\n            /*switch the state of espconn for next packet copy*/\n            if (pcb->state == ESTABLISHED)\n            \tprecv_cb->pespconn ->state = ESPCONN_CONNECT;\n        }\n\n        /*to prevent memory leaks, ensure that each allocated is deleted*/\n        os_free(pdata);\n        pdata = NULL;\n    }\n\n    if (err == ERR_OK && p == NULL) {\n        espconn_client_close(precv_cb, pcb);\n    }\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_write\n * Description  : write the packet which in the active connection's list.\n * Parameters   : arg -- the node pointer which reverse the packet\n * Returns      : ESPCONN_MEM: memory error\n * \t\t\t\t  ESPCONN_OK:have enough space for write packet\n*******************************************************************************/\nerr_t ICACHE_FLASH_ATTR espconn_tcp_write(void *arg)\n{\n\tespconn_msg *pwrite = arg;\n\terr_t err = ERR_OK;\n\tstruct tcp_pcb *pcb = pwrite->pcommon.pcb;\n\t/*for one active connection,limit the sender buffer space*/\n\tif (tcp_nagle_disabled(pcb) && (pcb->snd_queuelen >= TCP_SND_QUEUELEN))\n\t\treturn ESPCONN_MEM;\n\n\twhile (tcp_sndbuf(pcb) != 0){\n\t\tif (pwrite->pcommon.ptail != NULL) {\n\t\t\t/*Find the node whether in the list's tail or not*/\n\t\t\tif (pwrite->pcommon.ptail->unsent == 0) {\n\t\t\t\tpwrite->pcommon.ptail = pwrite->pcommon.ptail->pnext;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/*Send the packet for the active connection*/\n\t\t\terr = espconn_tcp_sent(pwrite, pwrite->pcommon.ptail->punsent,pwrite->pcommon.ptail->unsent);\n\t\t\tif (err != ERR_OK)\n\t\t\t\tbreak;\n\t\t} else\n\t\t\tbreak;\n\t}\n\treturn err;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_reconnect\n * Description  : reconnect with host\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR espconn_tcp_finish(void *arg)\n{\n\tespconn_msg *pfinish = arg;\n\tespconn_buf *premove = NULL;\n\tuint16 len = 0;\n\tespconn_tcp_write(pfinish);\n\twhile (pfinish->pcommon.pbuf != NULL){\n\t\tpremove = pfinish->pcommon.pbuf;\n\t\tpfinish->pcommon.pbuf->tot_len += len;\n\t\t/*application packet has been sent and acknowledged by the remote host,\n\t\t * to prevent memory leaks, ensure that each allocated is deleted*/\n\t\tif (premove->tot_len >= premove->len){\n\t\t\tespconn_pbuf_delete(&pfinish->pcommon.pbuf,premove);\n\t\t\tlen = premove->tot_len - premove->len;\n\t\t\tpfinish->pcommon.packet_info.sent_length = premove->len;\n\t\t\tos_free(premove);\n\t\t\tpremove = NULL;\n\t\t\tpfinish->pespconn->state = ESPCONN_CONNECT;\n\t\t\tif (pfinish->pespconn->sent_callback != NULL) {\n\t\t\t\tpfinish->pespconn->sent_callback(pfinish->pespconn);\n\t\t\t}\n\t\t\tpfinish->pcommon.packet_info.sent_length = len;\n\t\t} else\n\t\t\tbreak;\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_client_sent\n * Description  : Data has been sent and acknowledged by the remote host.\n *                This means that more data can be sent.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb for which data has been acknowledged\n *                len -- The amount of bytes acknowledged\n * Returns      : ERR_OK: try to send some data by calling tcp_output\n *                ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_client_sent(void *arg, struct tcp_pcb *pcb, u16_t len)\n{\n\tespconn_msg *psent_cb = arg;\n\n\tpsent_cb->pcommon.pcb = pcb;\n\tpsent_cb->pcommon.pbuf->tot_len += len;\n\tpsent_cb->pcommon.packet_info.sent_length = len;\n\n\t/*Send more data for one active connection*/\n\tespconn_tcp_finish(psent_cb);\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_client_err\n * Description  : The pcb had an error and is already deallocated.\n *                The argument might still be valid (if != NULL).\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                err -- Error code to indicate why the pcb has been closed\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_client_err(void *arg, err_t err)\n{\n\tespconn_msg *perr_cb = arg;\n\tstruct tcp_pcb *pcb = NULL;\n    LWIP_UNUSED_ARG(err);\n\n    if (perr_cb != NULL) {\n        pcb = perr_cb->pcommon.pcb;\n        perr_cb->pespconn->state = ESPCONN_CLOSE;\n        espconn_printf(\"espconn_client_err %d %d %d\\n\", pcb->state, pcb->nrtx, err);\n\n//        /*remove the node from the client's active connection list*/\n//        espconn_list_delete(&plink_active, perr_cb);\n\n        /*Set the error code depend on the error type and control block state*/\n        if (err == ERR_ABRT) {\n        \tswitch (pcb->state) {\n\t\t\t\t\tcase SYN_SENT:\n\t\t\t\t\t\tif (pcb->nrtx == TCP_SYNMAXRTX) {\n\t\t\t\t\t\t\tperr_cb->pcommon.err = ESPCONN_CONN;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tperr_cb->pcommon.err = err;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase ESTABLISHED:\n\t\t\t\t\t\tif (pcb->nrtx == TCP_MAXRTX) {\n\t\t\t\t\t\t\tperr_cb->pcommon.err = ESPCONN_TIMEOUT;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tperr_cb->pcommon.err = err;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase FIN_WAIT_1:\n\t\t\t\t\t\tif (pcb->nrtx == TCP_MAXRTX) {\n\t\t\t\t\t\t\tperr_cb->pcommon.err = ESPCONN_CLSD;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tperr_cb->pcommon.err = err;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase FIN_WAIT_2:\n\t\t\t\t\t\tperr_cb->pcommon.err = ESPCONN_CLSD;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CLOSED:\n\t\t\t\t\t\tperr_cb->pcommon.err = ESPCONN_CONN;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tperr_cb->pcommon.err = err;\n\t\t\t}\n        \t/*post the singer to the task for processing the connection*/\n        \tets_post(espconn_TaskPrio, SIG_ESPCONN_ERRER, (uint32_t)perr_cb);\n\t\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_client_connect\n * Description  : A new incoming connection has been connected.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                tpcb -- The connection pcb which is connected\n *                err -- An unused error code, always ERR_OK currently\n * Returns      : connection result\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_client_connect(void *arg, struct tcp_pcb *tpcb, err_t err)\n{\n    espconn_msg *pcon = arg;\n\n    espconn_printf(\"espconn_client_connect pcon %p tpcb %p\\n\", pcon, tpcb);\n    if (err == ERR_OK){\n    \t/*Reserve the remote information for current active connection*/\n\t\tpcon->pespconn->state = ESPCONN_CONNECT;\n\t\tpcon->pcommon.err = err;\n\t\tpcon->pcommon.pcb = tpcb;\n\t\tpcon->pcommon.local_port = tpcb->local_port;\n\t\tpcon->pcommon.local_ip = tpcb->local_ip.addr;\n\t\tpcon->pcommon.remote_port = tpcb->remote_port;\n\t\tpcon->pcommon.remote_ip[0] = ip4_addr1_16(&tpcb->remote_ip);\n\t\tpcon->pcommon.remote_ip[1] = ip4_addr2_16(&tpcb->remote_ip);\n\t\tpcon->pcommon.remote_ip[2] = ip4_addr3_16(&tpcb->remote_ip);\n\t\tpcon->pcommon.remote_ip[3] = ip4_addr4_16(&tpcb->remote_ip);\n\t\tpcon->pcommon.write_flag = true;\n\t\ttcp_arg(tpcb, (void *) pcon);\n\n\t\t/*Set the specify function that should be called\n\t\t * when TCP data has been successfully delivered,\n\t\t * when active connection receives data*/\n\t\ttcp_sent(tpcb, espconn_client_sent);\n\t\ttcp_recv(tpcb, espconn_client_recv);\n\t\t/*Disable Nagle algorithm default*/\n\t\ttcp_nagle_disable(tpcb);\n\t\t/*Default set the total number of espconn_buf on the unsent lists for one*/\n\t\tespconn_tcp_set_buf_count(pcon->pespconn, 1);\n\n\t\tif (pcon->pespconn->proto.tcp->connect_callback != NULL) {\n\t\t\tpcon->pespconn->proto.tcp->connect_callback(pcon->pespconn);\n\t\t}\n\n\t\t/*Enable keep alive option*/\n\t\tif (espconn_keepalive_disabled(pcon))\n\t\t\tespconn_keepalive_enable(tpcb);\n\n    } else{\n    \tos_printf(\"err in host connected (%s)\\n\",lwip_strerr(err));\n    }\n    return err;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_client\n * Description  : Initialize the client: set up a connect PCB and bind it to\n *                the defined port\n * Parameters   : espconn -- the espconn used to build client\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_tcp_client(struct espconn *espconn)\n{\n    struct tcp_pcb *pcb = NULL;\n    struct ip_addr ipaddr;\n    espconn_msg *pclient = NULL;\n\n    /*Creates a new client control message*/\n\tpclient = (espconn_msg *)os_zalloc(sizeof(espconn_msg));\n\tif (pclient == NULL){\n\t\treturn ESPCONN_MEM;\n \t}\n\n\t/*Set an IP address given for Little-endian.*/\n    IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0],\n    \t\tespconn->proto.tcp->remote_ip[1],\n    \t\tespconn->proto.tcp->remote_ip[2],\n    \t\tespconn->proto.tcp->remote_ip[3]);\n\n    /*Creates a new TCP protocol control block*/\n    pcb = tcp_new();\n\n    if (pcb == NULL) {\n    \t/*to prevent memory leaks, ensure that each allocated is deleted*/\n    \tos_free(pclient);\n    \tpclient = NULL;\n        return ESPCONN_MEM;\n    } else {\n\n    \t/*insert the node to the active connection list*/\n    \tespconn_list_creat(&plink_active, pclient);\n    \ttcp_arg(pcb, (void *)pclient);\n    \ttcp_err(pcb, espconn_client_err);\n    \tpclient->preverse = NULL;\n    \tpclient->pespconn = espconn;\n    \tpclient->pespconn->state = ESPCONN_WAIT;\n    \tpclient->pcommon.pcb = pcb;\n    \ttcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port);\n#if 0\n    \tpclient->pcommon.err = tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port);\n    \tif (pclient->pcommon.err != ERR_OK){\n    \t\t/*remove the node from the client's active connection list*/\n    \t\tespconn_list_delete(&plink_active, pclient);\n    \t\tmemp_free(MEMP_TCP_PCB, pcb);\n    \t\tos_free(pclient);\n    \t\tpclient = NULL;\n    \t\treturn ERR_USE;\n    \t}\n#endif\n        /*Establish the connection*/\n        pclient->pcommon.err = tcp_connect(pcb, &ipaddr,\n        \t\tpclient->pespconn->proto.tcp->remote_port, espconn_client_connect);\n        if (pclient->pcommon.err == ERR_RTE){\n\t\t\t/*remove the node from the client's active connection list*/\n\t\t\tespconn_list_delete(&plink_active, pclient);\n\t\t\tespconn_kill_pcb(pcb->local_port);\n\t\t\tos_free(pclient);\n\t\t\tpclient = NULL;\n\t\t\treturn ESPCONN_RTE;\n\t\t}\n        return pclient->pcommon.err;\n    }\n}\n\n///////////////////////////////server function/////////////////////////////////\n/******************************************************************************\n * FunctionName : espconn_server_close\n * Description  : The connection shall be actively closed.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- the pcb to close\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_server_close(void *arg, struct tcp_pcb *pcb)\n{\n    err_t err;\n    espconn_msg *psclose = arg;\n\n\tpsclose->pcommon.pcb = pcb;\n\t/*avoid recalling the disconnect function*/\n\ttcp_recv(pcb, NULL);\n\terr = tcp_close(pcb);\n\n    if (err != ERR_OK) {\n        /* closing failed, try again later */\n        tcp_recv(pcb, espconn_server_recv);\n    } else {\n        /* closing succeeded */\n        tcp_poll(pcb, NULL, 0);\n        tcp_sent(pcb, NULL);\n        tcp_err(pcb, NULL);\n        /*switch the state of espconn for application process*/\n        psclose->pespconn->state = ESPCONN_CLOSE;\n        ets_post(espconn_TaskPrio, SIG_ESPCONN_CLOSE, (uint32_t)psclose);\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_server_recv\n * Description  : Data has been received on this pcb.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb which received data\n *                p -- The received data (or NULL when the connection has been closed!)\n *                err -- An error code if there has been an error receiving\n * Returns      : ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\n{\n\tespconn_msg *precv_cb = arg;\n\n    tcp_arg(pcb, arg);\n    espconn_printf(\"server has application data received: %d\\n\", system_get_free_heap_size());\n    if (p != NULL) {\n    \t/*To update and advertise a larger window*/\n\t\tif(precv_cb->recv_hold_flag == 0)\n        \ttcp_recved(pcb, p->tot_len);\n\t\telse\n\t\t\tprecv_cb->recv_holded_buf_Len += p->tot_len;\n    }\n\n    if (err == ERR_OK && p != NULL) {\n    \tu8_t *data_ptr = NULL;\n    \tu32_t data_cntr = 0;\n    \t/*clear the count for connection timeout*/\n\t\tprecv_cb->pcommon.recv_check = 0;\n\t\t/*Copy the contents of a packet buffer to an application buffer.\n\t\t *to prevent memory leaks, ensure that each allocated is deleted*/\n        data_ptr = (u8_t *)os_zalloc(p ->tot_len + 1);\n        data_cntr = pbuf_copy_partial(p, data_ptr, p ->tot_len, 0);\n        pbuf_free(p);\n\n        if (data_cntr != 0) {\n        \t/*switch the state of espconn for application process*/\n        \tprecv_cb->pespconn ->state = ESPCONN_READ;\n        \tprecv_cb->pcommon.pcb = pcb;\n            if (precv_cb->pespconn->recv_callback != NULL) {\n            \tprecv_cb->pespconn->recv_callback(precv_cb->pespconn, data_ptr, data_cntr);\n            }\n\n            /*switch the state of espconn for next packet copy*/\n            if (pcb->state == ESTABLISHED)\n            \tprecv_cb->pespconn ->state = ESPCONN_CONNECT;\n        }\n\n        /*to prevent memory leaks, ensure that each allocated is deleted*/\n        os_free(data_ptr);\n        data_ptr = NULL;\n        espconn_printf(\"server's application data has been processed: %d\\n\", system_get_free_heap_size());\n    } else {\n        if (p != NULL) {\n            pbuf_free(p);\n        }\n\n        espconn_server_close(precv_cb, pcb);\n    }\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_server_sent\n * Description  : Data has been sent and acknowledged by the remote host.\n * This means that more data can be sent.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb for which data has been acknowledged\n *                len -- The amount of bytes acknowledged\n * Returns      : ERR_OK: try to send some data by calling tcp_output\n *                ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_server_sent(void *arg, struct tcp_pcb *pcb, u16_t len)\n{\n\tespconn_msg *psent_cb = arg;\n\n\tpsent_cb->pcommon.pcb = pcb;\n\tpsent_cb->pcommon.recv_check = 0;\n\tpsent_cb->pcommon.pbuf->tot_len += len;\n\tpsent_cb->pcommon.packet_info.sent_length = len;\n\n\t/*Send more data for one active connection*/\n\tespconn_tcp_finish(psent_cb);\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_server_poll\n * Description  : The poll function is called every 3nd second.\n * If there has been no data sent (which resets the retries) in 3 seconds, close.\n * If the last portion of a file has not been sent in 3 seconds, close.\n *\n * This could be increased, but we don't want to waste resources for bad connections.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb for which data has been acknowledged\n * Returns      : ERR_OK: try to send some data by calling tcp_output\n *                ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_server_poll(void *arg, struct tcp_pcb *pcb)\n{\n\tespconn_msg *pspoll_cb = arg;\n\n\t/*exception calling abandon the connection for send a RST frame*/\n    if (arg == NULL) {\n        tcp_abandon(pcb, 0);\n        tcp_poll(pcb, NULL, 0);\n        return ERR_OK;\n    }\n\n    espconn_printf(\"espconn_server_poll %d %d\\n\", pspoll_cb->pcommon.recv_check, pcb->state);\n    pspoll_cb->pcommon.pcb = pcb;\n    if (pcb->state == ESTABLISHED) {\n\t\tpspoll_cb->pcommon.recv_check++;\n\t\tif (pspoll_cb->pcommon.timeout != 0){/*no data sent in one active connection's set timeout, close.*/\n\t\t\tif (pspoll_cb->pcommon.recv_check >= pspoll_cb->pcommon.timeout) {\n\t\t\t\tpspoll_cb->pcommon.recv_check = 0;\n\t\t\t\tespconn_server_close(pspoll_cb, pcb);\n\t\t\t}\n\t\t} else {\n\t\t\tespconn_msg *ptime_msg = pserver_list;\n\t\t\twhile (ptime_msg != NULL) {\n\t\t\t\tif (ptime_msg->pespconn == pspoll_cb->preverse){\n\t\t\t\t\tif (ptime_msg->pcommon.timeout != 0){/*no data sent in server's set timeout, close.*/\n\t\t\t\t\t\tif (pspoll_cb->pcommon.recv_check >= ptime_msg->pcommon.timeout){\n\t\t\t\t\t\t\tpspoll_cb->pcommon.recv_check = 0;\n\t\t\t\t\t\t\tespconn_server_close(pspoll_cb, pcb);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {/*don't close for ever*/\n\t\t\t\t\t\tpspoll_cb->pcommon.recv_check = 0;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tptime_msg = ptime_msg->pnext;\n\t\t\t}\n\t\t}\n    } else {\n        espconn_server_close(pspoll_cb, pcb);\n    }\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : esponn_server_err\n * Description  : The pcb had an error and is already deallocated.\n *                The argument might still be valid (if != NULL).\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                err -- Error code to indicate why the pcb has been closed\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nesponn_server_err(void *arg, err_t err)\n{\n\tespconn_msg *pserr_cb = arg;\n\tstruct tcp_pcb *pcb = NULL;\n    if (pserr_cb != NULL) {\n\n    \tpcb = pserr_cb->pcommon.pcb;\n    \tpserr_cb->pespconn->state = ESPCONN_CLOSE;\n\n//\t\t/*remove the node from the server's active connection list*/\n//\t\tespconn_list_delete(&plink_active, pserr_cb);\n\n    \t/*Set the error code depend on the error type and control block state*/\n\t\tif (err == ERR_ABRT) {\n\t\t\tswitch (pcb->state) {\n\t\t\t\tcase SYN_RCVD:\n\t\t\t\t\tif (pcb->nrtx == TCP_SYNMAXRTX) {\n\t\t\t\t\t\tpserr_cb->pcommon.err = ESPCONN_CONN;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpserr_cb->pcommon.err = err;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ESTABLISHED:\n\t\t\t\t\tif (pcb->nrtx == TCP_MAXRTX) {\n\t\t\t\t\t\tpserr_cb->pcommon.err = ESPCONN_TIMEOUT;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpserr_cb->pcommon.err = err;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CLOSE_WAIT:\n\t\t\t\t\tif (pcb->nrtx == TCP_MAXRTX) {\n\t\t\t\t\t\tpserr_cb->pcommon.err = ESPCONN_CLSD;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpserr_cb->pcommon.err = err;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase LAST_ACK:\n\t\t\t\t\tpserr_cb->pcommon.err = ESPCONN_CLSD;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CLOSED:\n\t\t\t\t\tpserr_cb->pcommon.err = ESPCONN_CONN;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault :\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tpserr_cb->pcommon.err = err;\n\t\t}\n\t\t/*post the singer to the task for processing the connection*/\n\t\tets_post(espconn_TaskPrio, SIG_ESPCONN_ERRER, (uint32_t)pserr_cb);\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_accept\n * Description  : A new incoming connection has been accepted.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb which is accepted\n *                err -- An unused error code, always ERR_OK currently\n * Returns      : acception result\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err)\n{\n    struct espconn *espconn = arg;\n    espconn_msg *paccept = NULL;\n    remot_info *pinfo = NULL;\n    LWIP_UNUSED_ARG(err);\n\n    if (!espconn || !espconn->proto.tcp) {\n    \treturn ERR_ARG;\n    }\n\n    tcp_arg(pcb, paccept);\n    tcp_err(pcb, esponn_server_err);\n    /*Ensure the active connection is less than the count of active connections on the server*/\n    espconn_get_connection_info(espconn, &pinfo , 0);\n\tespconn_printf(\"espconn_tcp_accept link_cnt: %d\\n\", espconn->link_cnt);\n\tif (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn))\n\t\treturn ERR_ISCONN;\n\n\t/*Creates a new active connect control message*/\n    paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg));\n    tcp_arg(pcb, paccept);\n\n\tif (paccept == NULL)\n\t\treturn ERR_MEM;\n\t/*Insert the node to the active connection list*/\n\tespconn_list_creat(&plink_active, paccept);\n\n    paccept->preverse = espconn;\n\tpaccept->pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn));\n\tif (paccept->pespconn == NULL)\n\t\treturn ERR_MEM;\n\tpaccept->pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));\n\tif (paccept->pespconn->proto.tcp == NULL)\n\t\treturn ERR_MEM;\n\n\t/*Reserve the remote information for current active connection*/\n\tpaccept->pcommon.pcb = pcb;\n\n\tpaccept->pcommon.remote_port = pcb->remote_port;\n\tpaccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip);\n\tpaccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip);\n\tpaccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip);\n\tpaccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip);\n\tpaccept->pcommon.write_flag = true;\n\n\tos_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4);\n\tespconn->proto.tcp->remote_port = pcb->remote_port;\n\tespconn->state = ESPCONN_CONNECT;\n\tespconn_copy_partial(paccept->pespconn, espconn);\n\n\t/*Set the specify function that should be called\n\t * when TCP data has been successfully delivered,\n\t * when active connection receives data,\n\t * or periodically from active connection*/\n\ttcp_sent(pcb, espconn_server_sent);\n\ttcp_recv(pcb, espconn_server_recv);\n\ttcp_poll(pcb, espconn_server_poll, 8); /* every 1 seconds */\n\t/*Disable Nagle algorithm default*/\n\ttcp_nagle_disable(pcb);\n\t/*Default set the total number of espconn_buf on the unsent lists for one*/\n\tespconn_tcp_set_buf_count(paccept->pespconn, 1);\n\n\tif (paccept->pespconn->proto.tcp->connect_callback != NULL) {\n\t\tpaccept->pespconn->proto.tcp->connect_callback(paccept->pespconn);\n\t}\n\n\t/*Enable keep alive option*/\n\tif (espconn_keepalive_disabled(paccept))\n\t\tespconn_keepalive_enable(pcb);\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_server\n * Description  : Initialize the server: set up a listening PCB and bind it to\n *                the defined port\n * Parameters   : espconn -- the espconn used to build server\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_tcp_server(struct espconn *espconn)\n{\n    struct tcp_pcb *pcb = NULL;\n    espconn_msg *pserver = NULL;\n\n    /*Creates a new server control message*/\n    pserver = (espconn_msg *)os_zalloc(sizeof(espconn_msg));\n    if (pserver == NULL){\n    \treturn ESPCONN_MEM;\n    }\n\n    /*Creates a new TCP protocol control block*/\n    pcb = tcp_new();\n    if (pcb == NULL) {\n    \t/*to prevent memory leaks, ensure that each allocated is deleted*/\n    \tos_free(pserver);\n    \tpserver = NULL;\n        return ESPCONN_MEM;\n    } else {\n    \tstruct tcp_pcb *lpcb = NULL;\n    \t/*Binds the connection to a local port number and any IP address*/\n        tcp_bind(pcb, IP_ADDR_ANY, espconn->proto.tcp->local_port);\n        lpcb = pcb;\n        /*malloc and set the state of the connection to be LISTEN*/\n        pcb = tcp_listen(pcb);\n        if (pcb != NULL) {\n        \t/*insert the node to the active connection list*/\n        \tespconn_list_creat(&pserver_list, pserver);\n        \tpserver->preverse = pcb;\n        \tpserver->pespconn = espconn;\n        \tpserver->count_opt = MEMP_NUM_TCP_PCB;\n\t\t\tpserver->pcommon.timeout = 0x0a;\n            espconn ->state = ESPCONN_LISTEN;\n            /*set the specify argument that should be passed callback function*/\n            tcp_arg(pcb, (void *)espconn);\n            /*accept callback function to call for this control block*/\n            tcp_accept(pcb, espconn_tcp_accept);\n            return ESPCONN_OK;\n        } else {\n        \t/*to prevent memory leaks, ensure that each allocated is deleted*/\n        \tmemp_free(MEMP_TCP_PCB,lpcb);\n        \tos_free(pserver);\n        \tpserver = NULL;\n            return ESPCONN_MEM;\n        }\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_delete\n * Description  : delete the server: delete a listening PCB and free it\n * Parameters   : pdeletecon -- the espconn used to delete a server\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_tcp_delete(struct espconn *pdeletecon)\n{\n\terr_t err;\n\tremot_info *pinfo = NULL;\n\tespconn_msg *pdelete_msg = NULL;\n\tstruct tcp_pcb *pcb = NULL;\n\n\tif (pdeletecon == NULL)\n\t\treturn ESPCONN_ARG;\n\n\tespconn_get_connection_info(pdeletecon, &pinfo , 0);\n\t/*make sure all the active connection have been disconnect*/\n\tif (pdeletecon->link_cnt != 0)\n\t\treturn ESPCONN_INPROGRESS;\n\telse {\n\t\tespconn_printf(\"espconn_tcp_delete %p\\n\",pdeletecon);\n\t\tpdelete_msg = pserver_list;\n\t\twhile (pdelete_msg != NULL){\n\t\t\tif (pdelete_msg->pespconn == pdeletecon){\n\t\t\t\t/*remove the node from the client's active connection list*/\n\t\t\t\tespconn_list_delete(&pserver_list, pdelete_msg);\n\t\t\t\tpcb = pdelete_msg->preverse;\n\t\t\t\tos_printf(\"espconn_tcp_delete %d, %d\\n\",pcb->state, pcb->local_port);\n\t\t\t\tespconn_kill_pcb(pcb->local_port);\n\t\t\t\terr = tcp_close(pcb);\n\t\t\t\tos_free(pdelete_msg);\n\t\t\t\tpdelete_msg = NULL;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpdelete_msg = pdelete_msg->pnext;\n\t\t}\n\t\tif (err == ERR_OK)\n\t\t\treturn err;\n\t\telse\n\t\t\treturn ESPCONN_ARG;\n\t}\n}\n\n/******************************************************************************\n * FunctionName : espconn_init\n * Description  : used to init the function that should be used when\n * Parameters   : none\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_init(void)\n{\n  ets_task(espconn_Task, espconn_TaskPrio, espconn_TaskQueue, espconn_TaskQueueLen);\n}\n"
  },
  {
    "path": "app/lwip/app/espconn_udp.c",
    "content": "/******************************************************************************\r\n * Copyright 2013-2014 Espressif Systems (Wuxi)\r\n *\r\n * FileName: espconn_udp.c\r\n *\r\n * Description: udp proto interface\r\n *\r\n * Modification history:\r\n *     2014/3/31, v1.0 create this file.\r\n*******************************************************************************/\r\n\r\n#include \"ets_sys.h\"\r\n#include \"os_type.h\"\r\n//#include \"os.h\"\r\n\r\n#include \"lwip/inet.h\"\r\n#include \"lwip/err.h\"\r\n#include \"lwip/pbuf.h\"\r\n#include \"lwip/mem.h\"\r\n#include \"lwip/tcp_impl.h\"\r\n#include \"lwip/udp.h\"\r\n\r\n#include \"lwip/app/espconn_udp.h\"\r\n\r\n#ifdef MEMLEAK_DEBUG\r\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\r\n#endif\r\n\r\nextern espconn_msg *plink_active;\r\nextern uint8 default_interface;\r\n\r\nenum send_opt{\r\n\tESPCONN_SENDTO,\r\n\tESPCONN_SEND\r\n};\r\nstatic void ICACHE_FLASH_ATTR espconn_data_sentcb(struct espconn *pespconn)\r\n{\r\n    if (pespconn == NULL) {\r\n        return;\r\n    }\r\n\r\n    if (pespconn->sent_callback != NULL) {\r\n        pespconn->sent_callback(pespconn);\r\n    }\r\n}\r\n\r\nstatic void ICACHE_FLASH_ATTR espconn_data_sent(void *arg, enum send_opt opt)\r\n{\r\n    espconn_msg *psent = arg;\r\n\r\n    if (psent == NULL) {\r\n        return;\r\n    }\r\n\r\n    if (psent->pcommon.cntr == 0) {\r\n        psent->pespconn->state = ESPCONN_CONNECT;\r\n//        sys_timeout(10, espconn_data_sentcb, psent->pespconn);\r\n        espconn_data_sentcb(psent->pespconn);\r\n    } else {\r\n    \tif (opt == ESPCONN_SEND){\r\n    \t\tespconn_udp_sent(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr);\r\n    \t} else {\r\n    \t\tespconn_udp_sendto(arg, psent->pcommon.ptrbuf, psent->pcommon.cntr);\r\n    \t}\r\n    }\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_sent\r\n * Description  : sent data for client or server\r\n * Parameters   : void *arg -- client or server to send\r\n * \t\t\t\t  uint8* psent -- Data to send\r\n *                uint16 length -- Length of data to send\r\n * Returns      : return espconn error code.\r\n * - ESPCONN_OK. Successful. No error occured.\r\n * - ESPCONN_MEM. Out of memory.\r\n * - ESPCONN_RTE. Could not find route to destination address.\r\n * - More errors could be returned by lower protocol layers.\r\n*******************************************************************************/\r\nerr_t ICACHE_FLASH_ATTR\r\nespconn_udp_sent(void *arg, uint8 *psent, uint16 length)\r\n{\r\n    espconn_msg *pudp_sent = arg;\r\n    struct udp_pcb *upcb = pudp_sent->pcommon.pcb;\r\n    struct pbuf *p, *q ,*p_temp;\r\n    u8_t *data = NULL;\r\n    u16_t cnt = 0;\r\n    u16_t datalen = 0;\r\n    u16_t i = 0;\r\n    err_t err;\r\n    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %d %p\\n\", __LINE__, length, upcb));\r\n\r\n    if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) {\r\n        return ESPCONN_ARG;\r\n    }\r\n\r\n    if (1470 < length) {\r\n        datalen = 1470;\r\n    } else {\r\n        datalen = length;\r\n    }\r\n\r\n    p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);\r\n    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %p\\n\", __LINE__, p));\r\n\r\n    if (p != NULL) {\r\n        q = p;\r\n\r\n        while (q != NULL) {\r\n            data = (u8_t *)q->payload;\r\n            LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %p\\n\", __LINE__, data));\r\n\r\n            for (i = 0; i < q->len; i++) {\r\n                data[i] = ((u8_t *) psent)[cnt++];\r\n            }\r\n\r\n            q = q->next;\r\n        }\r\n    } else {\r\n        return ESPCONN_MEM;\r\n    }\r\n\r\n    upcb->remote_port = pudp_sent->pespconn->proto.udp->remote_port;\r\n    IP4_ADDR(&upcb->remote_ip, pudp_sent->pespconn->proto.udp->remote_ip[0],\r\n    \t\tpudp_sent->pespconn->proto.udp->remote_ip[1],\r\n    \t\tpudp_sent->pespconn->proto.udp->remote_ip[2],\r\n    \t\tpudp_sent->pespconn->proto.udp->remote_ip[3]);\r\n\r\n    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %x %d\\n\", __LINE__, upcb->remote_ip, upcb->remote_port));\r\n\r\n    struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00);\r\n    struct netif *ap_netif =  (struct netif *)eagle_lwip_getif(0x01);\r\n\t\t\r\n    if(wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL)\r\n    {\r\n    \tif(netif_is_up(sta_netif) && netif_is_up(ap_netif) && \\\r\n\t\t\tip_addr_isbroadcast(&upcb->remote_ip, sta_netif) && \\\r\n\t\t\tip_addr_isbroadcast(&upcb->remote_ip, ap_netif)) {\r\n\r\n    \t  p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);\r\n    \t  if (pbuf_copy (p_temp,p) != ERR_OK) {\r\n    \t\t  LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent: copying to new pbuf failed\\n\"));\r\n    \t\t  return ESPCONN_ARG;\r\n    \t  }\r\n\t\t  netif_set_default(sta_netif);\r\n\t\t  err = udp_send(upcb, p_temp);\r\n\t\t  pbuf_free(p_temp);\r\n\t\t  netif_set_default(ap_netif);\r\n    \t}\r\n    }\r\n\t      err = udp_send(upcb, p);\r\n\r\n    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %d\\n\", __LINE__, err));\r\n\r\n    if (p->ref != 0) {\r\n        LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %p\\n\", __LINE__, p));\r\n        pbuf_free(p);\r\n        pudp_sent->pcommon.ptrbuf = psent + datalen;\r\n        pudp_sent->pcommon.cntr = length - datalen;\r\n        espconn_data_sent(pudp_sent, ESPCONN_SEND);\r\n        if (err > 0)\r\n        \treturn ESPCONN_IF;\r\n        return err;\r\n    } else {\r\n    \tpbuf_free(p);\r\n    \treturn ESPCONN_RTE;\r\n    }\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_sendto\r\n * Description  : sent data for UDP\r\n * Parameters   : void *arg -- UDP to send\r\n * \t\t\t\t  uint8* psent -- Data to send\r\n *                uint16 length -- Length of data to send\r\n * Returns      : return espconn error code.\r\n * - ESPCONN_OK. Successful. No error occured.\r\n * - ESPCONN_MEM. Out of memory.\r\n * - ESPCONN_RTE. Could not find route to destination address.\r\n * - More errors could be returned by lower protocol layers.\r\n*******************************************************************************/\r\nerr_t ICACHE_FLASH_ATTR\r\nespconn_udp_sendto(void *arg, uint8 *psent, uint16 length)\r\n{\r\n    espconn_msg *pudp_sent = arg;\r\n    struct udp_pcb *upcb = pudp_sent->pcommon.pcb;\r\n    struct espconn *pespconn = pudp_sent->pespconn;\r\n    struct pbuf *p, *q ,*p_temp;\r\n    struct ip_addr dst_ip;\r\n    u16_t dst_port;\r\n    u8_t *data = NULL;\r\n    u16_t cnt = 0;\r\n    u16_t datalen = 0;\r\n    u16_t i = 0;\r\n    err_t err;\r\n    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %d %p\\n\", __LINE__, length, upcb));\r\n\r\n    if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) {\r\n        return ESPCONN_ARG;\r\n    }\r\n\r\n    if (1470 < length) {\r\n        datalen = 1470;\r\n    } else {\r\n        datalen = length;\r\n    }\r\n\r\n    p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);\r\n    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %p\\n\", __LINE__, p));\r\n\r\n    if (p != NULL) {\r\n        q = p;\r\n\r\n        while (q != NULL) {\r\n            data = (u8_t *)q->payload;\r\n            LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %p\\n\", __LINE__, data));\r\n\r\n            for (i = 0; i < q->len; i++) {\r\n                data[i] = ((u8_t *) psent)[cnt++];\r\n            }\r\n\r\n            q = q->next;\r\n        }\r\n    } else {\r\n        return ESPCONN_MEM;\r\n    }\r\n\r\n    dst_port = pespconn->proto.udp->remote_port;\r\n    IP4_ADDR(&dst_ip, pespconn->proto.udp->remote_ip[0],\r\n\t\t\tpespconn->proto.udp->remote_ip[1], pespconn->proto.udp->remote_ip[2],\r\n\t\t\tpespconn->proto.udp->remote_ip[3]);\r\n    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sent %d %x %d\\n\", __LINE__, upcb->remote_ip, upcb->remote_port));\r\n\r\n    struct netif *sta_netif = (struct netif *)eagle_lwip_getif(0x00);\r\n\tstruct netif *ap_netif =  (struct netif *)eagle_lwip_getif(0x01);\r\n\r\n    if(wifi_get_opmode() == ESPCONN_AP_STA && default_interface == ESPCONN_AP_STA && sta_netif != NULL && ap_netif != NULL)\r\n\t{\r\n\t\tif(netif_is_up(sta_netif) && netif_is_up(ap_netif) && \\\r\n\t\t\tip_addr_isbroadcast(&upcb->remote_ip, sta_netif) && \\\r\n\t\t\tip_addr_isbroadcast(&upcb->remote_ip, ap_netif)) {\r\n\r\n\t\t  p_temp = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);\r\n\t\t  if (pbuf_copy (p_temp,p) != ERR_OK) {\r\n\t\t\t  LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_sendto: copying to new pbuf failed\\n\"));\r\n\t\t\t  return ESPCONN_ARG;\r\n\t\t  }\r\n\t\t  netif_set_default(sta_netif);\r\n\t\t  err = udp_sendto(upcb, p_temp, &dst_ip, dst_port);\r\n\t\t  pbuf_free(p_temp);\r\n\t\t  netif_set_default(ap_netif);\r\n\t\t}\r\n\t}\r\n    err = udp_sendto(upcb, p, &dst_ip, dst_port);\r\n\r\n    if (p->ref != 0) {\r\n    \tpbuf_free(p);\r\n    \tpudp_sent->pcommon.ptrbuf = psent + datalen;\r\n\t\tpudp_sent->pcommon.cntr = length - datalen;\r\n\t\tif (err == ERR_OK)\r\n\t\t\tespconn_data_sent(pudp_sent, ESPCONN_SENDTO);\r\n\r\n\t\tif (err > 0)\r\n\t\t\treturn ESPCONN_IF;\r\n\t\treturn err;\r\n    } else {\r\n    \tpbuf_free(p);\r\n    \treturn ESPCONN_RTE;\r\n    }\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_server_recv\r\n * Description  : This callback will be called when receiving a datagram.\r\n * Parameters   : arg -- user supplied argument\r\n *                upcb -- the udp_pcb which received data\r\n *                p -- the packet buffer that was received\r\n *                addr -- the remote IP address from which the packet was received\r\n *                port -- the remote port from which the packet was received\r\n * Returns      : none\r\n*******************************************************************************/\r\nstatic void ICACHE_FLASH_ATTR\r\nespconn_udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p,\r\n                 struct ip_addr *addr, u16_t port)\r\n{\r\n    espconn_msg *precv = arg;\r\n    struct pbuf *q = NULL;\r\n    u8_t *pdata = NULL;\r\n    u16_t length = 0;\r\n    struct ip_info ipconfig;\r\n\r\n    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"espconn_udp_server_recv %d %p\\n\", __LINE__, upcb));\r\n\r\n    precv->pcommon.remote_ip[0] = ip4_addr1_16(addr);\r\n    precv->pcommon.remote_ip[1] = ip4_addr2_16(addr);\r\n    precv->pcommon.remote_ip[2] = ip4_addr3_16(addr);\r\n    precv->pcommon.remote_ip[3] = ip4_addr4_16(addr);\r\n    precv->pcommon.remote_port = port;\r\n    precv->pcommon.pcb = upcb;\r\n\r\n\tif (wifi_get_opmode() != 1) {\r\n\t\twifi_get_ip_info(1, &ipconfig);\r\n\r\n\t\tif (!ip_addr_netcmp((struct ip_addr *)precv->pespconn->proto.udp->remote_ip, &ipconfig.ip, &ipconfig.netmask)) {\r\n\t\t\twifi_get_ip_info(0, &ipconfig);\r\n\t\t}\r\n\t} else {\r\n\t\twifi_get_ip_info(0, &ipconfig);\r\n\t}\r\n\r\n\tprecv->pespconn->proto.udp->local_ip[0] = ip4_addr1_16(&ipconfig.ip);\r\n\tprecv->pespconn->proto.udp->local_ip[1] = ip4_addr2_16(&ipconfig.ip);\r\n\tprecv->pespconn->proto.udp->local_ip[2] = ip4_addr3_16(&ipconfig.ip);\r\n\tprecv->pespconn->proto.udp->local_ip[3] = ip4_addr4_16(&ipconfig.ip);\r\n\r\n    precv->pespconn->proto.udp->remote_ip[0] = precv->pcommon.remote_ip[0];\r\n    precv->pespconn->proto.udp->remote_ip[1] = precv->pcommon.remote_ip[1];\r\n    precv->pespconn->proto.udp->remote_ip[2] = precv->pcommon.remote_ip[2];\r\n    precv->pespconn->proto.udp->remote_ip[3] = precv->pcommon.remote_ip[3];\r\n    precv->pespconn->proto.udp->remote_port = port;\r\n\r\n    if (p != NULL) {\r\n    \tpdata = (u8_t *)os_zalloc(p ->tot_len + 1);\r\n    \tlength = pbuf_copy_partial(p, pdata, p ->tot_len, 0);\r\n    \tprecv->pcommon.pcb = upcb;\r\n        pbuf_free(p);\r\n\t\tif (length != 0) {\r\n\t\t\tif (precv->pespconn->recv_callback != NULL) {\r\n\t\t\t\tprecv->pespconn->recv_callback(precv->pespconn, pdata, length);\r\n\t\t\t}\r\n\t\t}\r\n\t\tos_free(pdata);\r\n    } else {\r\n        return;\r\n    }\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_disconnect\r\n * Description  : A new incoming connection has been disconnected.\r\n * Parameters   : espconn -- the espconn used to disconnect with host\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid ICACHE_FLASH_ATTR espconn_udp_disconnect(espconn_msg *pdiscon)\r\n{\r\n    if (pdiscon == NULL) {\r\n        return;\r\n    }\r\n\r\n    struct udp_pcb *upcb = pdiscon->pcommon.pcb;\r\n\r\n    udp_disconnect(upcb);\r\n\r\n    udp_remove(upcb);\r\n\r\n    espconn_list_delete(&plink_active, pdiscon);\r\n\r\n    os_free(pdiscon);\r\n    pdiscon = NULL;\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_udp_server\r\n * Description  : Initialize the server: set up a PCB and bind it to the port\r\n * Parameters   : pespconn -- the espconn used to build server\r\n * Returns      : none\r\n*******************************************************************************/\r\nsint8 ICACHE_FLASH_ATTR\r\nespconn_udp_server(struct espconn *pespconn)\r\n{\r\n    struct udp_pcb *upcb = NULL;\r\n    espconn_msg *pserver = NULL;\r\n    upcb = udp_new();\r\n\r\n    if (upcb == NULL) {\r\n        return ESPCONN_MEM;\r\n    } else {\r\n        pserver = (espconn_msg *)os_zalloc(sizeof(espconn_msg));\r\n\r\n        if (pserver == NULL) {\r\n            udp_remove(upcb);\r\n            return ESPCONN_MEM;\r\n        }\r\n\r\n        pserver->pcommon.pcb = upcb;\r\n        pserver->pespconn = pespconn;\r\n        espconn_list_creat(&plink_active, pserver);\r\n        udp_bind(upcb, IP_ADDR_ANY, pserver->pespconn->proto.udp->local_port);\r\n        udp_recv(upcb, espconn_udp_recv, (void *)pserver);\r\n        return ESPCONN_OK;\r\n    }\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_igmp_leave\r\n * Description  : leave a multicast group\r\n * Parameters   : host_ip -- the ip address of udp server\r\n * \t\t\t\t  multicast_ip -- multicast ip given by user\r\n * Returns      : none\r\n*******************************************************************************/\r\nsint8 ICACHE_FLASH_ATTR\r\nespconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip)\r\n{\r\n    if (igmp_leavegroup(host_ip, multicast_ip) != ERR_OK) {\r\n        LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"udp_leave_multigrup failed!\\n\"));\r\n        return -1;\r\n    };\r\n\r\n    return ESPCONN_OK;\r\n}\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_igmp_join\r\n * Description  : join a multicast group\r\n * Parameters   : host_ip -- the ip address of udp server\r\n * \t\t\t\t  multicast_ip -- multicast ip given by user\r\n * Returns      : none\r\n*******************************************************************************/\r\nsint8 ICACHE_FLASH_ATTR\r\nespconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip)\r\n{\r\n    if (igmp_joingroup(host_ip, multicast_ip) != ERR_OK) {\r\n        LWIP_DEBUGF(ESPCONN_UDP_DEBUG, (\"udp_join_multigrup failed!\\n\"));\r\n        return -1;\r\n    };\r\n\r\n    /* join to any IP address at the port  */\r\n    return ESPCONN_OK;\r\n}\r\n"
  },
  {
    "path": "app/lwip/app/netio.c",
    "content": "/**\r\n * @file\r\n * MetIO Server\r\n *\r\n */\r\n\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 *\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. The name of the author may not be used to endorse or promote products\r\n *    derived from this software without specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r\n * OF SUCH DAMAGE.\r\n *\r\n * This file is part of the lwIP TCP/IP stack.\r\n *\r\n */\r\n#include \"lwip/opt.h\"\r\n\r\n#if LWIP_TCP\r\n#include \"lwip/tcp.h\"\r\n\r\n#ifdef MEMLEAK_DEBUG\r\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\r\n#endif\r\n\r\n/*\r\n * This implements a netio server.\r\n *  The client sends a command word (4 bytes) then a data length word (4 bytes).\r\n *  If the command is \"receive\", the server is to consume \"data length\" bytes into\r\n *   a circular buffer until the first byte is non-zero, then it is to consume\r\n *   another command/data pair.\r\n *  If the command is \"send\", the server is to send \"data length\" bytes from a circular\r\n *   buffer with the first byte being zero, until \"some time\" (6 seconds in the\r\n *   current netio126.zip download) has passed and then send one final buffer with\r\n *   the first byte being non-zero. Then it is to consume another command/data pair.\r\n */\r\n\r\n/* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */\r\n\r\n/* implementation options */\r\n#define NETIO_BUF_SIZE              (4 * 1024)\r\n#define NETIO_USE_STATIC_BUF        0\r\n\r\n/* NetIO server state definition */\r\n#define NETIO_STATE_WAIT_FOR_CMD    0\r\n#define NETIO_STATE_RECV_DATA       1\r\n#define NETIO_STATE_SEND_DATA       2\r\n#define NETIO_STATE_SEND_DATA_LAST  3\r\n#define NETIO_STATE_DONE            4\r\n\r\nstruct netio_state {\r\n  u32_t  state;\r\n  u32_t  cmd;\r\n  u32_t  data_len;\r\n  u32_t  cntr;\r\n  u8_t * buf_ptr;\r\n  u32_t  buf_pos;\r\n  u32_t  first_byte;\r\n  u32_t  time_stamp;\r\n};\r\n\r\n/* NetIO command protocol definition */\r\n#define NETIO_CMD_QUIT              0\r\n#define NETIO_CMD_C2S               1\r\n#define NETIO_CMD_S2C               2\r\n#define NETIO_CMD_RES               3\r\n\r\nstatic err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);\r\n\r\nstatic void ICACHE_FLASH_ATTR\r\nnetio_close(void *arg, struct tcp_pcb *pcb)\r\n{\r\n  err_t err;\r\n\r\n  struct netio_state *ns = arg;\r\n  ns->state = NETIO_STATE_DONE;\r\n  tcp_recv(pcb, NULL);\r\n  err = tcp_close(pcb);\r\n\r\n  if (err != ERR_OK) {\r\n    /* closing failed, try again later */\r\n    tcp_recv(pcb, netio_recv);\r\n  } else {\r\n    /* closing succeeded */\r\n#if NETIO_USE_STATIC_BUF != 1\r\n    if(ns->buf_ptr != NULL){\r\n      mem_free(ns->buf_ptr);\r\n    }\r\n#endif\r\n    tcp_arg(pcb, NULL);\r\n    tcp_poll(pcb, NULL, 0);\r\n    tcp_sent(pcb, NULL);\r\n    if (arg != NULL) {\r\n      mem_free(arg);\r\n    }\r\n  }\r\n}\r\n\r\nstatic err_t ICACHE_FLASH_ATTR\r\nnetio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\r\n{\r\n  struct netio_state *ns = arg;\r\n  u8_t * data_ptr;\r\n  u32_t data_cntr;\r\n  struct pbuf *q = p;\r\n  u16_t len;\r\n\r\n  if (p != NULL) {\r\n    tcp_recved(pcb, p->tot_len);\r\n  }\r\n\r\n  if (err == ERR_OK && q != NULL) {\r\n\r\n    while (q != NULL) {\r\n      data_cntr = q->len;\r\n      data_ptr = q->payload;\r\n      while (data_cntr--) {\r\n        if (ns->state == NETIO_STATE_DONE){\r\n          netio_close(ns, pcb);\r\n          break;\r\n        } else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) {\r\n          if (ns->cntr < 4) {\r\n            /* build up the CMD field */\r\n            ns->cmd <<= 8;\r\n            ns->cmd |= *data_ptr++;\r\n            ns->cntr++;\r\n          } else if (ns->cntr < 8) {\r\n            /* build up the DATA field */\r\n            ns->data_len <<= 8;\r\n            ns->data_len |= *data_ptr++;\r\n            ns->cntr++;\r\n\r\n            if (ns->cntr == 8) {\r\n              /* now we have full command and data words */\r\n              ns->cntr = 0;\r\n              ns->buf_pos = 0;\r\n              ns->buf_ptr[0] = 0;\r\n              if (ns->cmd == NETIO_CMD_C2S) {\r\n                ns->state = NETIO_STATE_RECV_DATA;\r\n              } else if (ns->cmd == NETIO_CMD_S2C) {\r\n                ns->state = NETIO_STATE_SEND_DATA;\r\n                /* start timer */\r\n                ns->time_stamp = sys_now();\r\n                /* send first round of data */\r\n\r\n                len = tcp_sndbuf(pcb);\r\n                len = LWIP_MIN(len, ns->data_len - ns->cntr);\r\n                len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);\r\n\r\n                do {\r\n                  err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);\r\n                  if (err == ERR_MEM) {\r\n                    len /= 2;\r\n                  }\r\n                } while ((err == ERR_MEM) && (len > 1));\r\n\r\n                ns->buf_pos += len;\r\n                ns->cntr    += len;\r\n\r\n              } else {\r\n                /* unrecognized command, punt */\r\n                ns->cntr = 0;\r\n                ns->buf_pos = 0;\r\n                ns->buf_ptr[0] = 0;\r\n                netio_close(ns, pcb);\r\n                break;\r\n              }\r\n            }\r\n          } else {\r\n            /* in trouble... shouldn't be in this state! */\r\n          }\r\n\r\n        } else if (ns->state == NETIO_STATE_RECV_DATA) {\r\n\r\n          if(ns->cntr == 0){\r\n            /* save the first byte of this new round of data\r\n             * this will not match ns->buf_ptr[0] in the case that\r\n             *   NETIO_BUF_SIZE is less than ns->data_len.\r\n             */\r\n            ns->first_byte = *data_ptr;\r\n          }\r\n\r\n          ns->buf_ptr[ns->buf_pos++] = *data_ptr++;\r\n          ns->cntr++;\r\n\r\n          if (ns->buf_pos == NETIO_BUF_SIZE) {\r\n            /* circularize the buffer */\r\n            ns->buf_pos = 0;\r\n          }\r\n\r\n          if(ns->cntr == ns->data_len){\r\n            ns->cntr = 0;\r\n            if (ns->first_byte != 0) {\r\n              /* if this last round did not start with 0,\r\n               *  go look for another command */\r\n              ns->state = NETIO_STATE_WAIT_FOR_CMD;\r\n              ns->data_len = 0;\r\n              ns->cmd = 0;\r\n              /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */\r\n            } else {\r\n              /* stay here and wait on more data */\r\n            }\r\n          }\r\n\r\n        } else if (ns->state == NETIO_STATE_SEND_DATA\r\n            || ns->state == NETIO_STATE_SEND_DATA_LAST) {\r\n          /* I don't think this should happen... */\r\n        } else {\r\n          /* done / quit */\r\n          netio_close(ns, pcb);\r\n          break;\r\n        } /* end of ns->state condition */\r\n      } /* end of while data still in this pbuf */\r\n\r\n      q = q->next;\r\n    }\r\n\r\n    pbuf_free(p);\r\n\r\n  } else {\r\n\r\n    /* error or closed by other side */\r\n    if (p != NULL) {\r\n      pbuf_free(p);\r\n    }\r\n\r\n    /* close the connection */\r\n    netio_close(ns, pcb);\r\n\r\n  }\r\n  return ERR_OK;\r\n\r\n}\r\n\r\nstatic err_t ICACHE_FLASH_ATTR\r\nnetio_sent(void *arg, struct tcp_pcb *pcb, u16_t len)\r\n{\r\n  struct netio_state *ns = arg;\r\n  err_t err = ERR_OK;\r\n\r\n  if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) {\r\n    /* done with this round of sending */\r\n    ns->buf_pos = 0;\r\n    ns->cntr = 0;\r\n\r\n    /* check if timer expired */\r\n    if (sys_now() - ns->time_stamp > 600) {\r\n      ns->buf_ptr[0] = 1;\r\n      ns->state = NETIO_STATE_SEND_DATA_LAST;\r\n    } else {\r\n      ns->buf_ptr[0] = 0;\r\n    }\r\n  }\r\n\r\n  if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){\r\n    len = tcp_sndbuf(pcb);\r\n    len = LWIP_MIN(len, ns->data_len - ns->cntr);\r\n    len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);\r\n\r\n    if(ns->cntr < ns->data_len){\r\n      do {\r\n        err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);\r\n        if (err == ERR_MEM) {\r\n          len /= 2;\r\n        }\r\n      } while ((err == ERR_MEM) && (len > 1));\r\n\r\n      ns->buf_pos += len;\r\n      if(ns->buf_pos >= NETIO_BUF_SIZE){\r\n        ns->buf_pos = 0;\r\n      }\r\n\r\n      ns->cntr += len;\r\n    }\r\n  }\r\n\r\n  if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){\r\n    /* we have buffered up all our data to send this last round, go look for a command */\r\n   ns->state = NETIO_STATE_WAIT_FOR_CMD;\r\n   ns->cntr  = 0;\r\n   /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */\r\n  }\r\n\r\n  return ERR_OK;\r\n}\r\n\r\nstatic err_t ICACHE_FLASH_ATTR\r\nnetio_poll(void *arg, struct tcp_pcb *pcb)\r\n{\r\n  struct netio_state * ns = arg;\r\n  if(ns->state == NETIO_STATE_SEND_DATA){\r\n\r\n  } else if(ns->state == NETIO_STATE_DONE){\r\n    netio_close(ns, pcb);\r\n  }\r\n\r\n  return ERR_OK;\r\n\r\n}\r\n\r\n#if NETIO_USE_STATIC_BUF == 1\r\nstatic u8_t netio_buf[NETIO_BUF_SIZE];\r\n#endif\r\n\r\nstatic err_t ICACHE_FLASH_ATTR\r\nnetio_accept(void *arg, struct tcp_pcb *pcb, err_t err)\r\n{\r\n  struct netio_state * ns;\r\n\r\n  LWIP_UNUSED_ARG(err);\r\n\r\n  ns = (struct netio_state *)mem_malloc(sizeof(struct netio_state));\r\n\r\n  if(ns == NULL){\r\n    return ERR_MEM;\r\n  }\r\n\r\n  ns->state = NETIO_STATE_WAIT_FOR_CMD;\r\n  ns->data_len = 0;\r\n  ns->cmd = 0;\r\n  ns->cntr = 0;\r\n  ns->buf_pos = 0;\r\n#if NETIO_USE_STATIC_BUF == 1\r\n  ns->buf_ptr = netio_buf;\r\n#else\r\n  ns->buf_ptr = (u8_t *)mem_malloc(NETIO_BUF_SIZE);\r\n\r\n  if(ns->buf_ptr == NULL){\r\n    mem_free(ns);\r\n    return ERR_MEM;\r\n  }\r\n#endif\r\n\r\n  ns->buf_ptr[0] = 0;\r\n\r\n  tcp_arg(pcb, ns);\r\n  tcp_sent(pcb, netio_sent);\r\n  tcp_recv(pcb, netio_recv);\r\n  tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */\r\n  return ERR_OK;\r\n}\r\n\r\nvoid ICACHE_FLASH_ATTR netio_init(void)\r\n{\r\n  struct tcp_pcb *pcb;\r\n\r\n  pcb = tcp_new();\r\n  tcp_bind(pcb, IP_ADDR_ANY, 18767);\r\n  pcb = tcp_listen(pcb);\r\n  tcp_accept(pcb, netio_accept);\r\n}\r\n\r\n#endif /* LWIP_TCP */\r\n"
  },
  {
    "path": "app/lwip/app/ping.c",
    "content": "/**\n * @file\n * Ping sender module\n *\n */\n\n/*\n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n */\n\n/** \n * This is an example of a \"ping\" sender (with raw API and socket API).\n * It can be used as a start point to maintain opened a network connection, or\n * like a network \"watchdog\" for your device.\n *\n */\n\n/*\n * copyright (c) 2010 - 2011 Espressif System\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/mem.h\"\n#include \"lwip/raw.h\"\n#include \"lwip/icmp.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/timers.h\"\n#include \"lwip/inet_chksum.h\"\n#include \"os_type.h\"\n#include \"osapi.h\"\n\n#include \"lwip/app/ping.h\"\n\n#if PING_USE_SOCKETS\n#include \"lwip/sockets.h\"\n#include \"lwip/inet.h\"\n#endif /* PING_USE_SOCKETS */\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/* ping variables */\nstatic u16_t ping_seq_num = 0;\nstatic u32_t ping_time;\n\nstatic void ICACHE_FLASH_ATTR ping_timeout(void* arg)\n{\n\tstruct ping_msg *pingmsg = (struct ping_msg *)arg;\n\tpingmsg->timeout_count ++;\n\tif (pingmsg->ping_opt->recv_function == NULL){\n\t\tos_printf(\"ping timeout\\n\");\n\t} else {\n\t\tstruct ping_resp pingresp;\n\t\tos_bzero(&pingresp, sizeof(struct ping_resp));\n\t\tpingresp.ping_err = -1;\n\t\tpingmsg->ping_opt->recv_function(pingmsg->ping_opt, (void*)&pingresp);\n\t}\n}\n\n/** Prepare a echo ICMP request */\nstatic void ICACHE_FLASH_ATTR\nping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)\n{\n  size_t i = 0;\n  size_t data_len = len - sizeof(struct icmp_echo_hdr);\n\n  ICMPH_TYPE_SET(iecho, ICMP_ECHO);\n  ICMPH_CODE_SET(iecho, 0);\n  iecho->chksum = 0;\n  iecho->id     = PING_ID;\n  ++ ping_seq_num;\n  if (ping_seq_num == 0x7fff)\n\t  ping_seq_num = 0;\n\n  iecho->seqno  = htons(ping_seq_num);\n\n  /* fill the additional data buffer with some data */\n  for(i = 0; i < data_len; i++) {\n    ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;\n  }\n\n  iecho->chksum = inet_chksum(iecho, len);\n}\n\nstatic void ICACHE_FLASH_ATTR\nping_prepare_er(struct icmp_echo_hdr *iecho, u16_t len)\n{\n\n\tICMPH_TYPE_SET(iecho, ICMP_ER);\n\tICMPH_CODE_SET(iecho, 0);\n\tiecho->chksum = 0;\n\n\tiecho->chksum = inet_chksum(iecho, len);\n}\n\n/* Ping using the raw ip */\nstatic u8_t ICACHE_FLASH_ATTR\nping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)\n{\n  struct icmp_echo_hdr *iecho = NULL;\n  static u16_t seqno = 0;\n  struct ping_msg *pingmsg = (struct ping_msg*)arg;\n\n  LWIP_UNUSED_ARG(arg);\n  LWIP_UNUSED_ARG(pcb);\n  LWIP_UNUSED_ARG(addr);\n  LWIP_ASSERT(\"p != NULL\", p != NULL);\n\n  if (pbuf_header( p, -PBUF_IP_HLEN)==0) {\n    iecho = (struct icmp_echo_hdr *)p->payload;\n\n    if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && iecho->type == ICMP_ER) {\n      LWIP_DEBUGF( PING_DEBUG, (\"ping: recv \"));\n      ip_addr_debug_print(PING_DEBUG, addr);\n      LWIP_DEBUGF( PING_DEBUG, (\" %\"U32_F\" ms\\n\", (sys_now()-ping_time)));\n\t  if (iecho->seqno != seqno){\n\t\t  /* do some ping result processing */\n\t\t  {\n\t\t\t  struct ip_hdr *iphdr = NULL;\n\t\t\t  char ipaddrstr[16];\n\t\t\t  ip_addr_t source_ip;\n\t\t\t  sys_untimeout(ping_timeout, pingmsg);\n\t\t\t  os_bzero(&source_ip, sizeof(ip_addr_t));\n\t\t\t  os_bzero(ipaddrstr, sizeof(ipaddrstr));\n\t\t\t  uint32 delay = system_relative_time(pingmsg->ping_sent);\n\t\t\t  delay /= PING_COARSE;\n\t\t\t  iphdr = (struct ip_hdr*)((u8*)iecho - PBUF_IP_HLEN);\n\t\t\t  source_ip.addr = iphdr->src.addr;\n\t\t\t  ipaddr_ntoa_r(&source_ip,ipaddrstr, sizeof(ipaddrstr));\n\t\t\t  if (pingmsg->ping_opt->recv_function == NULL){\n\t\t\t\t  os_printf(\"recv %s: byte = %d, time = %d ms, seq = %d\\n\",ipaddrstr, PING_DATA_SIZE, delay, ntohs(iecho->seqno));\n\t\t\t  } else {\n\t\t\t\t  struct ping_resp pingresp;\n\t\t\t\t  os_bzero(&pingresp, sizeof(struct ping_resp));\n\t\t\t\t  pingresp.bytes = PING_DATA_SIZE;\n\t\t\t\t  pingresp.resp_time = delay;\n\t\t\t\t  pingresp.seqno = ntohs(iecho->seqno);\n\t\t\t\t  pingresp.ping_err = 0;\n\t\t\t\t  pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp);\n\t\t\t  }\n\t\t  }\n\t\t  seqno = iecho->seqno;\n\t  }\n\n      PING_RESULT(1);\n      pbuf_free(p);\n      return 1; /* eat the packet */\n    }\n//    } else if(iecho->type == ICMP_ECHO){\n//        struct pbuf *q = NULL;\n//        os_printf(\"receive ping request:seq=%d\\n\", ntohs(iecho->seqno));\n//        q = pbuf_alloc(PBUF_IP, (u16_t)p->tot_len, PBUF_RAM);\n//        if (q!=NULL) {\n//            pbuf_copy(q, p);\n//            iecho = (struct icmp_echo_hdr *)q->payload;\n//            ping_prepare_er(iecho, q->tot_len);\n//            raw_sendto(pcb, q, addr);\n//            pbuf_free(q);\n//        }\n//        pbuf_free(p);\n//        return 1;\n//    }\n  }\n\n  return 0; /* don't eat the packet */\n}\n\nstatic void ICACHE_FLASH_ATTR\nping_send(struct raw_pcb *raw, ip_addr_t *addr)\n{\n  struct pbuf *p = NULL;\n  struct icmp_echo_hdr *iecho = NULL;\n  size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE;\n\n  LWIP_DEBUGF( PING_DEBUG, (\"ping: send \"));\n  ip_addr_debug_print(PING_DEBUG, addr);\n  LWIP_DEBUGF( PING_DEBUG, (\"\\n\"));\n  LWIP_ASSERT(\"ping_size <= 0xffff\", ping_size <= 0xffff);\n\n  p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM);\n  if (!p) {\n    return;\n  }\n  if ((p->len == p->tot_len) && (p->next == NULL)) {\n    iecho = (struct icmp_echo_hdr *)p->payload;\n\n    ping_prepare_echo(iecho, (u16_t)ping_size);\n\n    raw_sendto(raw, p, addr);\n    ping_time = sys_now();\n  }\n  pbuf_free(p);\n}\n\nstatic void ICACHE_FLASH_ATTR\nping_coarse_tmr(void *arg)\n{\n\tstruct ping_msg *pingmsg = (struct ping_msg*)arg;\n\tstruct ping_option *ping_opt= NULL;\n\tstruct ping_resp pingresp;\n\tip_addr_t ping_target;\n\n\tLWIP_ASSERT(\"ping_timeout: no pcb given!\", pingmsg != NULL);\n\tping_target.addr = pingmsg->ping_opt->ip;\n\tping_opt = pingmsg->ping_opt;\n\tif (--pingmsg->sent_count != 0){\n\t\tpingmsg ->ping_sent = system_get_time();\n\t\tping_send(pingmsg->ping_pcb, &ping_target);\n\n\t\tsys_timeout(PING_TIMEOUT_MS, ping_timeout, pingmsg);\n\t\tsys_timeout(pingmsg->coarse_time, ping_coarse_tmr, pingmsg);\n\t} else {\n\t\tuint32 delay = system_relative_time(pingmsg->ping_start);\n\t\tdelay /= PING_COARSE;\n//\t\tping_seq_num = 0;\n\t\tif (ping_opt->sent_function == NULL){\n\t\t\tos_printf(\"ping %d, timeout %d, total payload %d bytes, %d ms\\n\",\n\t\t\t\t\tpingmsg->max_count, pingmsg->timeout_count, PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count),delay);\n\t\t} else {\n\t\t\tos_bzero(&pingresp, sizeof(struct ping_resp));\n\t\t\tpingresp.total_count = pingmsg->max_count;\n\t\t\tpingresp.timeout_count = pingmsg->timeout_count;\n\t\t\tpingresp.total_bytes = PING_DATA_SIZE*(pingmsg->max_count - pingmsg->timeout_count);\n\t\t\tpingresp.total_time = delay;\n\t\t\tpingresp.ping_err = 0;\n\t\t}\n\t\tsys_untimeout(ping_coarse_tmr, pingmsg);\n\t\traw_remove(pingmsg->ping_pcb);\n\t\tos_free(pingmsg);\n\t\tif (ping_opt->sent_function != NULL)\n\t\t\tping_opt->sent_function(ping_opt,(uint8*)&pingresp);\n\t}\n}\n\nstatic bool ICACHE_FLASH_ATTR\nping_raw_init(struct ping_msg *pingmsg)\n{\n\tif (pingmsg == NULL)\n\t\treturn false;\n\n\tip_addr_t ping_target;\n\tpingmsg->ping_pcb = raw_new(IP_PROTO_ICMP);\n\tLWIP_ASSERT(\"ping_pcb != NULL\", pingmsg->ping_pcb != NULL);\n\n\traw_recv(pingmsg->ping_pcb, ping_recv, pingmsg);\n\traw_bind(pingmsg->ping_pcb, IP_ADDR_ANY);\n\n\tping_target.addr = pingmsg->ping_opt->ip;\n\tpingmsg ->ping_sent = system_get_time();\n\tping_send(pingmsg->ping_pcb, &ping_target);\n\n\tsys_timeout(PING_TIMEOUT_MS, ping_timeout, pingmsg);\n\tsys_timeout(pingmsg->coarse_time, ping_coarse_tmr, pingmsg);\n\treturn true;\n}\n\nbool ICACHE_FLASH_ATTR\nping_start(struct ping_option *ping_opt)\n{\n\tstruct ping_msg *pingmsg = NULL;\n\tpingmsg = (struct ping_msg *)os_zalloc(sizeof(struct ping_msg));\n\tif (pingmsg == NULL || ping_opt == NULL)\n\t\treturn false;\n\n\tpingmsg->ping_opt = ping_opt;\n\tif (ping_opt->count != 0)\n\t\tpingmsg->max_count = ping_opt->count;\n\telse\n\t\tpingmsg->max_count = DEFAULT_PING_MAX_COUNT;\n\n\tif (ping_opt->coarse_time != 0)\n\t\tpingmsg->coarse_time = ping_opt->coarse_time * PING_COARSE;\n\telse\n\t\tpingmsg->coarse_time = PING_COARSE;\n\n\tpingmsg->ping_start = system_get_time();\n\tpingmsg->sent_count = pingmsg->max_count;\n\treturn ping_raw_init(pingmsg);\n}\n\nbool ICACHE_FLASH_ATTR\nping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv)\n{\n\tif (ping_opt == NULL)\n\t\treturn false;\n\n\tping_opt ->recv_function = ping_recv;\n\treturn true;\n}\n\nbool ICACHE_FLASH_ATTR\nping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent)\n{\n\tif (ping_opt == NULL)\n\t\treturn false;\n\n\tping_opt ->sent_function = ping_sent;\n\treturn true;\n}\n\n#endif /* LWIP_RAW */\n"
  },
  {
    "path": "app/lwip/core/Makefile",
    "content": "\r\n#############################################################\r\n# Required variables for each makefile\r\n# Discard this section from all parent makefiles\r\n# Expected variables (with automatic defaults):\r\n#   CSRCS (all \"C\" files in the dir)\r\n#   SUBDIRS (all subdirs with a Makefile)\r\n#   GEN_LIBS - list of libs to be generated ()\r\n#   GEN_IMAGES - list of images to be generated ()\r\n#   COMPONENTS_xxx - a list of libs/objs in the form\r\n#     subdir/lib to be extracted and rolled up into\r\n#     a generated lib/image xxx.a ()\r\n#\r\nifndef PDIR\r\n\r\nGEN_LIBS = liblwipcore.a\r\n\r\nendif\r\n\r\n\r\n#############################################################\r\n# Configuration i.e. compile options etc.\r\n# Target specific stuff (defines etc.) goes in here!\r\n# Generally values applying to a tree are captured in the\r\n#   makefile at its root level - these are then overridden\r\n#   for a subtree within the makefile rooted therein\r\n#\r\n#DEFINES += \r\n\r\n#############################################################\r\n# Recursion Magic - Don't touch this!!\r\n#\r\n# Each subtree potentially has an include directory\r\n#   corresponding to the common APIs applicable to modules\r\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\r\n#   of a module can only contain the include directories up\r\n#   its parent path, and not its siblings\r\n#\r\n# Required for each makefile to inherit from the parent\r\n#\r\n\r\nINCLUDES := $(INCLUDES) -I $(PDIR)include\r\nINCLUDES += -I ./\r\nPDIR := ../$(PDIR)\r\nsinclude $(PDIR)Makefile\r\n\r\n"
  },
  {
    "path": "app/lwip/core/def.c",
    "content": "/**\n * @file\n * Common functions used throughout the stack.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Simon Goldschmidt\n *\n */\n\n#include \"lwip/opt.h\"\n#include \"lwip/def.h\"\n\n/**\n * These are reference implementations of the byte swapping functions.\n * Again with the aim of being simple, correct and fully portable.\n * Byte swapping is the second thing you would want to optimize. You will\n * need to port it to your architecture and in your cc.h:\n * \n * #define LWIP_PLATFORM_BYTESWAP 1\n * #define LWIP_PLATFORM_HTONS(x) <your_htons>\n * #define LWIP_PLATFORM_HTONL(x) <your_htonl>\n *\n * Note ntohs() and ntohl() are merely references to the htonx counterparts.\n */\n\n#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)\n\n/**\n * Convert an u16_t from host- to network byte order.\n *\n * @param n u16_t in host byte order\n * @return n in network byte order\n */\nu16_t\nlwip_htons(u16_t n)\n{\n  return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);\n}\n\n/**\n * Convert an u16_t from network- to host byte order.\n *\n * @param n u16_t in network byte order\n * @return n in host byte order\n */\nu16_t\nlwip_ntohs(u16_t n)\n{\n  return lwip_htons(n);\n}\n\n/**\n * Convert an u32_t from host- to network byte order.\n *\n * @param n u32_t in host byte order\n * @return n in network byte order\n */\nu32_t\nlwip_htonl(u32_t n)\n{\n  return ((n & 0xff) << 24) |\n    ((n & 0xff00) << 8) |\n    ((n & 0xff0000UL) >> 8) |\n    ((n & 0xff000000UL) >> 24);\n}\n\n/**\n * Convert an u32_t from network- to host byte order.\n *\n * @param n u32_t in network byte order\n * @return n in host byte order\n */\nu32_t\nlwip_ntohl(u32_t n)\n{\n  return lwip_htonl(n);\n}\n\n#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */\n"
  },
  {
    "path": "app/lwip/core/dhcp.c",
    "content": "/**\n * @file\n * Dynamic Host Configuration Protocol client\n *\n */\n\n/*\n *\n * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>\n * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is a contribution to the lwIP TCP/IP stack.\n * The Swedish Institute of Computer Science and Adam Dunkels\n * are specifically granted permission to redistribute this\n * source code.\n *\n * Author: Leon Woestenberg <leon.woestenberg@gmx.net>\n *\n * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform\n * with RFC 2131 and RFC 2132.\n *\n * TODO:\n * - Support for interfaces other than Ethernet (SLIP, PPP, ...)\n *\n * Please coordinate changes and requests with Leon Woestenberg\n * <leon.woestenberg@gmx.net>\n *\n * Integration with your code:\n *\n * In lwip/dhcp.h\n * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)\n * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)\n *\n * Then have your application call dhcp_coarse_tmr() and\n * dhcp_fine_tmr() on the defined intervals.\n *\n * dhcp_start(struct netif *netif);\n * starts a DHCP client instance which configures the interface by\n * obtaining an IP address lease and maintaining it.\n *\n * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)\n * to remove the DHCP client.\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/stats.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/def.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/dhcp.h\"\n#include \"lwip/autoip.h\"\n#include \"lwip/dns.h\"\n#include \"netif/etharp.h\"\n\n#include <string.h>\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/** Default for DHCP_GLOBAL_XID is 0xABCD0000\n * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.\n *  #define DHCP_GLOBAL_XID_HEADER \"stdlib.h\"\n *  #define DHCP_GLOBAL_XID rand()\n */\n#ifdef DHCP_GLOBAL_XID_HEADER\n#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */\n#endif\n\n/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU\n * MTU is checked to be big enough in dhcp_start */\n#define DHCP_MAX_MSG_LEN(netif)        (netif->mtu)\n#define DHCP_MAX_MSG_LEN_MIN_REQUIRED  576\n/** Minimum length for reply before packet is parsed */\n#define DHCP_MIN_REPLY_LEN             44\n\n#define REBOOT_TRIES 2\n\n/** Option handling: options are parsed in dhcp_parse_reply\n * and saved in an array where other functions can load them from.\n * This might be moved into the struct dhcp (not necessarily since\n * lwIP is single-threaded and the array is only used while in recv\n * callback). */\n#define DHCP_OPTION_IDX_OVERLOAD    0\n#define DHCP_OPTION_IDX_MSG_TYPE    1\n#define DHCP_OPTION_IDX_SERVER_ID   2\n#define DHCP_OPTION_IDX_LEASE_TIME  3\n#define DHCP_OPTION_IDX_T1          4\n#define DHCP_OPTION_IDX_T2          5\n#define DHCP_OPTION_IDX_SUBNET_MASK 6\n#define DHCP_OPTION_IDX_ROUTER      7\n#define DHCP_OPTION_IDX_DNS_SERVER\t8\n#define DHCP_OPTION_IDX_MAX         (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS)\n\n/** Holds the decoded option values, only valid while in dhcp_recv.\n    @todo: move this into struct dhcp? */\nu32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX];\n/** Holds a flag which option was received and is contained in dhcp_rx_options_val,\n    only valid while in dhcp_recv.\n    @todo: move this into struct dhcp? */\nu8_t  dhcp_rx_options_given[DHCP_OPTION_IDX_MAX];\n\n#define dhcp_option_given(dhcp, idx)          (dhcp_rx_options_given[idx] != 0)\n#define dhcp_got_option(dhcp, idx)            (dhcp_rx_options_given[idx] = 1)\n#define dhcp_clear_option(dhcp, idx)          (dhcp_rx_options_given[idx] = 0)\n#define dhcp_clear_all_options(dhcp)          (os_memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given)))\n#define dhcp_get_option_value(dhcp, idx)      (dhcp_rx_options_val[idx])\n#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val))\n\n\n/* DHCP client state machine functions */\nstatic err_t dhcp_discover(struct netif *netif);\nstatic err_t dhcp_select(struct netif *netif);\nstatic void dhcp_bind(struct netif *netif);\n#if DHCP_DOES_ARP_CHECK\nstatic err_t dhcp_decline(struct netif *netif);\n#endif /* DHCP_DOES_ARP_CHECK */\nstatic err_t dhcp_rebind(struct netif *netif);\nstatic err_t dhcp_reboot(struct netif *netif);\nstatic void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);\n\n/* receive, unfold, parse and free incoming messages */\nstatic void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);\n\n/* set the DHCP timers */\nstatic void dhcp_timeout(struct netif *netif);\nstatic void dhcp_t1_timeout(struct netif *netif);\nstatic void dhcp_t2_timeout(struct netif *netif);\n\n/* build outgoing messages */\n/* create a DHCP message, fill in common headers */\nstatic err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type);\n/* free a DHCP request */\nstatic void dhcp_delete_msg(struct dhcp *dhcp);\n/* add a DHCP option (type, then length in bytes) */\nstatic void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);\n/* add option values */\nstatic void dhcp_option_byte(struct dhcp *dhcp, u8_t value);\nstatic void dhcp_option_short(struct dhcp *dhcp, u16_t value);\nstatic void dhcp_option_long(struct dhcp *dhcp, u32_t value);\n/* always add the DHCP options trailer to end and pad */\nstatic void dhcp_option_trailer(struct dhcp *dhcp);\n\n/**\n * Back-off the DHCP client (because of a received NAK response).\n *\n * Back-off the DHCP client because of a received NAK. Receiving a\n * NAK means the client asked for something non-sensible, for\n * example when it tries to renew a lease obtained on another network.\n *\n * We clear any existing set IP address and restart DHCP negotiation\n * afresh (as per RFC2131 3.2.3).\n *\n * @param netif the netif under DHCP control\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_handle_nak(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_handle_nak(netif=%p) %c%c%\"U16_F\"\\n\", \n    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\n  /* Set the interface down since the address must no longer be used, as per RFC2131 */\n  netif_set_down(netif);\n  /* remove IP address from interface */\n  netif_set_ipaddr(netif, IP_ADDR_ANY);\n  netif_set_gw(netif, IP_ADDR_ANY);\n  netif_set_netmask(netif, IP_ADDR_ANY); \n  /* Change to a defined state */\n  dhcp_set_state(dhcp, DHCP_BACKING_OFF);\n  /* We can immediately restart discovery */\n  dhcp_discover(netif);\n}\n\n#if DHCP_DOES_ARP_CHECK\n/**\n * Checks if the offered IP address is already in use.\n *\n * It does so by sending an ARP request for the offered address and\n * entering CHECKING state. If no ARP reply is received within a small\n * interval, the address is assumed to be free for use by us.\n *\n * @param netif the netif under DHCP control\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_check(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  err_t result;\n  u16_t msecs;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_check(netif=%p) %c%c\\n\", (void *)netif, (s16_t)netif->name[0],\n    (s16_t)netif->name[1]));\n  dhcp_set_state(dhcp, DHCP_CHECKING);\n  /* create an ARP query for the offered IP address, expecting that no host\n     responds, as the IP address should not be in use. */\n  result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);\n  if (result != ERR_OK) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, (\"dhcp_check: could not perform ARP query\\n\"));\n  }\n  dhcp->tries++;\n  msecs = 500;\n  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_check(): set request timeout %\"U16_F\" msecs\\n\", msecs));\n}\n#endif /* DHCP_DOES_ARP_CHECK */\n\n/**\n * Remember the configuration offered by a DHCP server.\n *\n * @param netif the netif under DHCP control\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_handle_offer(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_handle_offer(netif=%p) %c%c%\"U16_F\"\\n\",\n    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\n  /* obtain the server address */\n  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) {\n    ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID)));\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, (\"dhcp_handle_offer(): server 0x%08\"X32_F\"\\n\",\n      ip4_addr_get_u32(&dhcp->server_ip_addr)));\n    /* remember offered address */\n    ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, (\"dhcp_handle_offer(): offer for 0x%08\"X32_F\"\\n\",\n      ip4_addr_get_u32(&dhcp->offered_ip_addr)));\n\n    dhcp_select(netif);\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,\n      (\"dhcp_handle_offer(netif=%p) did not get server ID!\\n\", (void*)netif));\n  }\n}\n\n/**\n * Select a DHCP server offer out of all offers.\n *\n * Simply select the first offer received.\n *\n * @param netif the netif under DHCP control\n * @return lwIP specific error (see error.h)\n */\nstatic err_t ICACHE_FLASH_ATTR\ndhcp_select(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  err_t result;\n  u16_t msecs;\n\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_select(netif=%p) %c%c%\"U16_F\"\\n\", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\n  dhcp_set_state(dhcp, DHCP_REQUESTING);\n\n  /* create and initialize the DHCP message header */\n  result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);\n  if (result == ERR_OK) {\n    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\n    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));\n\n    /* MUST request the offered IP address */\n    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\n    dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));\n\n    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\n    dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr)));\n\n    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 12/*num options*/);\n    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);\n    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);\n    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);\n    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);\n    dhcp_option_byte(dhcp, DHCP_OPTION_DOMAIN_NAME);\n        dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINS);\n        dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINT);\n        dhcp_option_byte(dhcp, DHCP_OPTION_NB_TIS);\n        dhcp_option_byte(dhcp, DHCP_OPTION_PRD);\n        dhcp_option_byte(dhcp, DHCP_OPTION_STATIC_ROUTER);\n        dhcp_option_byte(dhcp, DHCP_OPTION_CLASSLESS_STATIC_ROUTER);\n        dhcp_option_byte(dhcp, DHCP_OPTION_VSN);\n\n#if LWIP_NETIF_HOSTNAME\n    if (netif->hostname != NULL) {\n      const char *p = (const char*)netif->hostname;\n      u8_t namelen = (u8_t)os_strlen(p);\n      if (namelen > 0) {\n        LWIP_ASSERT(\"DHCP: hostname is too long!\", namelen < 255);\n        dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);\n        while (*p) {\n          dhcp_option_byte(dhcp, *p++);\n        }\n      }\n    }\n#endif /* LWIP_NETIF_HOSTNAME */\n\n    dhcp_option_trailer(dhcp);\n    /* shrink the pbuf to the actual content length */\n    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\n\n    /* send broadcast to any DHCP server */\n    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\n    dhcp_delete_msg(dhcp);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_select: REQUESTING\\n\"));\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, (\"dhcp_select: could not allocate DHCP request\\n\"));\n  }\n  dhcp->tries++;\n  msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;\n  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, (\"dhcp_select(): set request timeout %\"U16_F\" msecs\\n\", msecs));\n  return result;\n}\n\n/**\n * The DHCP timer that checks for lease renewal/rebind timeouts.\n */\nvoid ICACHE_FLASH_ATTR\ndhcp_coarse_tmr()\n{\n  struct netif *netif = netif_list;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_coarse_tmr()\\n\"));\n  /* iterate through all network interfaces */\n  while (netif != NULL) {\n    /* only act on DHCP configured interfaces */\n    if (netif->dhcp != NULL) {\n      /* timer is active (non zero), and triggers (zeroes) now? */\n      if (netif->dhcp->t2_timeout-- == 1) {\n        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_coarse_tmr(): t2 timeout\\n\"));\n        /* this clients' rebind timeout triggered */\n        dhcp_t2_timeout(netif);\n      /* timer is active (non zero), and triggers (zeroes) now */\n      } else if (netif->dhcp->t1_timeout-- == 1) {\n        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_coarse_tmr(): t1 timeout\\n\"));\n        /* this clients' renewal timeout triggered */\n        dhcp_t1_timeout(netif);\n      }\n    }\n    /* proceed to next netif */\n    netif = netif->next;\n  }\n}\n\n/**\n * DHCP transaction timeout handling\n *\n * A DHCP server is expected to respond within a short period of time.\n * This timer checks whether an outstanding DHCP request is timed out.\n */\nvoid ICACHE_FLASH_ATTR\ndhcp_fine_tmr()\n{\n  struct netif *netif = netif_list;\n  /* loop through netif's */\n  while (netif != NULL) {\n    /* only act on DHCP configured interfaces */\n    if (netif->dhcp != NULL) {\n      /*add DHCP retries processing by LiuHan*/\n      if (DHCP_MAXRTX != 0) {\n    \t  if (netif->dhcp->tries >= DHCP_MAXRTX){\n\t\t\t  os_printf(\"DHCP timeout\\n\");\n\t\t\t  if (netif->dhcp_event != NULL)\n\t\t\t\t  netif->dhcp_event();\n\t\t\t  break;\n\t\t  }\n      }\n      /* timer is active (non zero), and is about to trigger now */      \n      if (netif->dhcp->request_timeout > 1) {\n        netif->dhcp->request_timeout--;\n      }\n      else if (netif->dhcp->request_timeout == 1) {\n        netif->dhcp->request_timeout--;\n        /* { netif->dhcp->request_timeout == 0 } */\n        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_fine_tmr(): request timeout\\n\"));\n        /* this client's request timeout triggered */\n        dhcp_timeout(netif);\n      }\n    }\n    /* proceed to next network interface */\n    netif = netif->next;\n  }\n\n}\n\n/**\n * A DHCP negotiation transaction, or ARP request, has timed out.\n *\n * The timer that was started with the DHCP or ARP request has\n * timed out, indicating no response was received in time.\n *\n * @param netif the netif under DHCP control\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_timeout(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_timeout()\\n\"));\n  /* back-off period has passed, or server selection timed out */\n  if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_timeout(): restarting discovery\\n\"));\n    dhcp_discover(netif);\n  /* receiving the requested lease timed out */\n  } else if (dhcp->state == DHCP_REQUESTING) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_timeout(): REQUESTING, DHCP request timed out\\n\"));\n    if (dhcp->tries <= 5) {\n      dhcp_select(netif);\n    } else {\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_timeout(): REQUESTING, releasing, restarting\\n\"));\n      dhcp_release(netif);\n      dhcp_discover(netif);\n    }\n#if DHCP_DOES_ARP_CHECK\n  /* received no ARP reply for the offered address (which is good) */\n  } else if (dhcp->state == DHCP_CHECKING) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_timeout(): CHECKING, ARP request timed out\\n\"));\n    if (dhcp->tries <= 1) {\n      dhcp_check(netif);\n    /* no ARP replies on the offered address,\n       looks like the IP address is indeed free */\n    } else {\n      /* bind the interface to the offered address */\n      dhcp_bind(netif);\n    }\n#endif /* DHCP_DOES_ARP_CHECK */\n  }\n  /* did not get response to renew request? */\n  else if (dhcp->state == DHCP_RENEWING) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_timeout(): RENEWING, DHCP request timed out\\n\"));\n    /* just retry renewal */\n    /* note that the rebind timer will eventually time-out if renew does not work */\n    dhcp_renew(netif);\n  /* did not get response to rebind request? */\n  } else if (dhcp->state == DHCP_REBINDING) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_timeout(): REBINDING, DHCP request timed out\\n\"));\n    if (dhcp->tries <= 8) {\n      dhcp_rebind(netif);\n    } else {\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_timeout(): RELEASING, DISCOVERING\\n\"));\n      dhcp_release(netif);\n      dhcp_discover(netif);\n    }\n  } else if (dhcp->state == DHCP_REBOOTING) {\n    if (dhcp->tries < REBOOT_TRIES) {\n      dhcp_reboot(netif);\n    } else {\n      dhcp_discover(netif);\n    }\n  }\n}\n\n/**\n * The renewal period has timed out.\n *\n * @param netif the netif under DHCP control\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_t1_timeout(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, (\"dhcp_t1_timeout()\\n\"));\n  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) ||\n      (dhcp->state == DHCP_RENEWING)) {\n    /* just retry to renew - note that the rebind timer (t2) will\n     * eventually time-out if renew tries fail. */\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n                (\"dhcp_t1_timeout(): must renew\\n\"));\n    /* This slightly different to RFC2131: DHCPREQUEST will be sent from state\n       DHCP_RENEWING, not DHCP_BOUND */\n    dhcp_renew(netif);\n  }\n}\n\n/**\n * The rebind period has timed out.\n *\n * @param netif the netif under DHCP control\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_t2_timeout(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_t2_timeout()\\n\"));\n  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) ||\n      (dhcp->state == DHCP_RENEWING)) {\n    /* just retry to rebind */\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n                (\"dhcp_t2_timeout(): must rebind\\n\"));\n    /* This slightly different to RFC2131: DHCPREQUEST will be sent from state\n       DHCP_REBINDING, not DHCP_BOUND */\n    dhcp_rebind(netif);\n  }\n}\n\n/**\n * Handle a DHCP ACK packet\n *\n * @param netif the netif under DHCP control\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_handle_ack(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n#if LWIP_DNS\n  u8_t n;\n#endif /* LWIP_DNS */\n\n  /* clear options we might not get from the ACK */\n  ip_addr_set_zero(&dhcp->offered_sn_mask);\n  ip_addr_set_zero(&dhcp->offered_gw_addr);\n#if LWIP_DHCP_BOOTP_FILE\n  ip_addr_set_zero(&dhcp->offered_si_addr);\n#endif /* LWIP_DHCP_BOOTP_FILE */\n\n  /* lease time given? */\n  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) {\n    /* remember offered lease time */\n    dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME);\n  }\n  /* renewal period given? */\n  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) {\n    /* remember given renewal period */\n    dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1);\n  } else {\n    /* calculate safe periods for renewal */\n    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;\n  }\n\n  /* renewal period given? */\n  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) {\n    /* remember given rebind period */\n    dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2);\n  } else {\n    /* calculate safe periods for rebinding */\n    dhcp->offered_t2_rebind = dhcp->offered_t0_lease;\n  }\n\n  /* (y)our internet address */\n  ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr);\n\n#if LWIP_DHCP_BOOTP_FILE\n  /* copy boot server address,\n     boot file name copied in dhcp_parse_reply if not overloaded */\n  ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr);\n#endif /* LWIP_DHCP_BOOTP_FILE */\n\n  /* subnet mask given? */\n  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) {\n    /* remember given subnet mask */\n    ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)));\n    dhcp->subnet_mask_given = 1;\n  } else {\n    dhcp->subnet_mask_given = 0;\n  }\n\n  /* gateway router */\n  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) {\n    ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER)));\n  }\n  \n#if LWIP_DNS\n  /* DNS servers */\n  n = 0;\n  while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) {\n    ip_addr_t dns_addr;\n    ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));\n    dns_setserver(n, &dns_addr);\n    n++;\n  }\n#endif /* LWIP_DNS */\n}\n\n/** Set a statically allocated struct dhcp to work with.\n * Using this prevents dhcp_start to allocate it using mem_malloc.\n *\n * @param netif the netif for which to set the struct dhcp\n * @param dhcp (uninitialised) dhcp struct allocated by the application\n */\nvoid ICACHE_FLASH_ATTR\ndhcp_set_struct(struct netif *netif, struct dhcp *dhcp)\n{\n  LWIP_ASSERT(\"netif != NULL\", netif != NULL);\n  LWIP_ASSERT(\"dhcp != NULL\", dhcp != NULL);\n  LWIP_ASSERT(\"netif already has a struct dhcp set\", netif->dhcp == NULL);\n\n  /* clear data structure */\n  os_memset(dhcp, 0, sizeof(struct dhcp));\n  /* dhcp_set_state(&dhcp, DHCP_OFF); */\n  netif->dhcp = dhcp;\n}\n\n/** Removes a struct dhcp from a netif.\n *\n * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the\n *            struct dhcp since the memory is passed back to the heap.\n *\n * @param netif the netif from which to remove the struct dhcp\n */\nvoid ICACHE_FLASH_ATTR dhcp_cleanup(struct netif *netif)\n{\n  LWIP_ASSERT(\"netif != NULL\", netif != NULL);\n\n  if (netif->dhcp != NULL) {\n    mem_free(netif->dhcp);\n    netif->dhcp = NULL;\n  }\n}\n\n/**\n * Start DHCP negotiation for a network interface.\n *\n * If no DHCP client instance was attached to this interface,\n * a new client is created first. If a DHCP client instance\n * was already present, it restarts negotiation.\n *\n * @param netif The lwIP network interface\n * @return lwIP error code\n * - ERR_OK - No error\n * - ERR_MEM - Out of memory\n */\nerr_t ICACHE_FLASH_ATTR\ndhcp_start(struct netif *netif)\n{\n  struct dhcp *dhcp;\n  err_t result = ERR_OK;\n  LWIP_ERROR(\"netif != NULL\", (netif != NULL), return ERR_ARG;);\n  dhcp = netif->dhcp;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_start(netif=%p) %c%c%\"U16_F\"\\n\", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\n  /* Remove the flag that says this netif is handled by DHCP,\n     it is set when we succeeded starting. */\n  netif->flags &= ~NETIF_FLAG_DHCP;\n\n  /* check hwtype of the netif */\n  if ((netif->flags & NETIF_FLAG_ETHARP) == 0) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_start(): No ETHARP netif\\n\"));\n    return ERR_ARG;\n  }\n\n  /* check MTU of the netif */\n  if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_start(): Cannot use this netif with DHCP: MTU is too small\\n\"));\n    return ERR_MEM;\n  }\n\n  /* no DHCP client attached yet? */\n  if (dhcp == NULL) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_start(): starting new DHCP client\\n\"));\n    dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));\n    if (dhcp == NULL) {\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_start(): could not allocate dhcp\\n\"));\n      return ERR_MEM;\n    }\n    /* store this dhcp client in the netif */\n    netif->dhcp = dhcp;\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_start(): allocated dhcp\"));\n  /* already has DHCP client attached */\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_start(): restarting DHCP configuration\\n\"));\n    if (dhcp->pcb != NULL) {\n      udp_remove(dhcp->pcb);\n    }\n    LWIP_ASSERT(\"pbuf p_out wasn't freed\", dhcp->p_out == NULL);\n    LWIP_ASSERT(\"reply wasn't freed\", dhcp->msg_in == NULL );\n  }\n    \n  /* clear data structure */\n  os_memset(dhcp, 0, sizeof(struct dhcp));\n  /* dhcp_set_state(&dhcp, DHCP_OFF); */\n  /* allocate UDP PCB */\n  dhcp->pcb = udp_new();\n  if (dhcp->pcb == NULL) {\n    LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, (\"dhcp_start(): could not obtain pcb\\n\"));\n    return ERR_MEM;\n  }\n  dhcp->pcb->so_options |= SOF_BROADCAST;\n  /* set up local and remote port for the pcb */\n  udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\n  udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\n  /* set up the recv callback and argument */\n  udp_recv(dhcp->pcb, dhcp_recv, netif);\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_start(): starting DHCP configuration\\n\"));\n  /* (re)start the DHCP negotiation */\n  result = dhcp_discover(netif);\n  if (result != ERR_OK) {\n    /* free resources allocated above */\n    dhcp_stop(netif);\n    return ERR_MEM;\n  }\n  /* Set the flag that says this netif is handled by DHCP. */\n  netif->flags |= NETIF_FLAG_DHCP;\n  return result;\n}\n\n/**\n * Inform a DHCP server of our manual configuration.\n *\n * This informs DHCP servers of our fixed IP address configuration\n * by sending an INFORM message. It does not involve DHCP address\n * configuration, it is just here to be nice to the network.\n *\n * @param netif The lwIP network interface\n */\nvoid ICACHE_FLASH_ATTR\ndhcp_inform(struct netif *netif)\n{\n  struct dhcp dhcp;\n  err_t result = ERR_OK;\n  struct udp_pcb *pcb;\n\n  LWIP_ERROR(\"netif != NULL\", (netif != NULL), return;);\n\n  os_memset(&dhcp, 0, sizeof(struct dhcp));\n  dhcp_set_state(&dhcp, DHCP_INFORM);\n\n  if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) {\n    /* re-use existing pcb */\n    pcb = netif->dhcp->pcb;\n  } else {\n    pcb = udp_new();\n    if (pcb == NULL) {\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"dhcp_inform(): could not obtain pcb\"));\n      return;\n    }\n    dhcp.pcb = pcb;\n    dhcp.pcb->so_options |= SOF_BROADCAST;\n    udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_inform(): created new udp pcb\\n\"));\n  }\n  /* create and initialize the DHCP message header */\n  result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM);\n  if (result == ERR_OK) {\n    dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\n    dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif));\n\n    dhcp_option_trailer(&dhcp);\n\n    pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len);\n\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_inform: INFORMING\\n\"));\n    udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\n    dhcp_delete_msg(&dhcp);\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"dhcp_inform: could not allocate DHCP request\\n\"));\n  }\n\n  if (dhcp.pcb != NULL) {\n    /* otherwise, the existing pcb was used */\n    udp_remove(dhcp.pcb);\n  }\n}\n\n/** Handle a possible change in the network configuration.\n *\n * This enters the REBOOTING state to verify that the currently bound\n * address is still valid.\n */\nvoid ICACHE_FLASH_ATTR\ndhcp_network_changed(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  if (!dhcp)\n    return;\n  switch (dhcp->state) {\n  case DHCP_REBINDING:\n  case DHCP_RENEWING:\n  case DHCP_BOUND:\n  case DHCP_REBOOTING:\n    netif_set_down(netif);\n    dhcp->tries = 0;\n    dhcp_reboot(netif);\n    break;\n  case DHCP_OFF:\n    /* stay off */\n    break;\n  default:\n    dhcp->tries = 0;\n#if LWIP_DHCP_AUTOIP_COOP\n    if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {\n      autoip_stop(netif);\n      dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;\n    }\n#endif /* LWIP_DHCP_AUTOIP_COOP */\n    dhcp_discover(netif);\n    break;\n  }\n}\n\n#if DHCP_DOES_ARP_CHECK\n/**\n * Match an ARP reply with the offered IP address.\n *\n * @param netif the network interface on which the reply was received\n * @param addr The IP address we received a reply from\n */\nvoid ICACHE_FLASH_ATTR dhcp_arp_reply(struct netif *netif, ip_addr_t *addr)\n{\n  LWIP_ERROR(\"netif != NULL\", (netif != NULL), return;);\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_arp_reply()\\n\"));\n  /* is a DHCP client doing an ARP check? */\n  if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_arp_reply(): CHECKING, arp reply for 0x%08\"X32_F\"\\n\",\n      ip4_addr_get_u32(addr)));\n    /* did a host respond with the address we\n       were offered by the DHCP server? */\n    if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {\n      /* we will not accept the offered address */\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,\n        (\"dhcp_arp_reply(): arp reply matched with offered address, declining\\n\"));\n      dhcp_decline(netif);\n    }\n  }\n}\n\n/**\n * Decline an offered lease.\n *\n * Tell the DHCP server we do not accept the offered address.\n * One reason to decline the lease is when we find out the address\n * is already in use by another host (through ARP).\n *\n * @param netif the netif under DHCP control\n */\nstatic err_t ICACHE_FLASH_ATTR\ndhcp_decline(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  err_t result = ERR_OK;\n  u16_t msecs;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_decline()\\n\"));\n  dhcp_set_state(dhcp, DHCP_BACKING_OFF);\n  /* create and initialize the DHCP message header */\n  result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE);\n  if (result == ERR_OK) {\n    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\n    dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));\n\n    dhcp_option_trailer(dhcp);\n    /* resize pbuf to reflect true size of options */\n    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\n\n    /* per section 4.4.4, broadcast DECLINE messages */\n    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\n    dhcp_delete_msg(dhcp);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_decline: BACKING OFF\\n\"));\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,\n      (\"dhcp_decline: could not allocate DHCP request\\n\"));\n  }\n  dhcp->tries++;\n  msecs = 10*1000;\n  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_decline(): set request timeout %\"U16_F\" msecs\\n\", msecs));\n  return result;\n}\n#endif /* DHCP_DOES_ARP_CHECK */\n\n\n/**\n * Start the DHCP process, discover a DHCP server.\n *\n * @param netif the netif under DHCP control\n */\nstatic err_t ICACHE_FLASH_ATTR\ndhcp_discover(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  err_t result = ERR_OK;\n  u16_t msecs;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_discover()\\n\"));\n  ip_addr_set_any(&dhcp->offered_ip_addr);\n  dhcp_set_state(dhcp, DHCP_SELECTING);\n  /* create and initialize the DHCP message header */\n  result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER);\n  if (result == ERR_OK) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_discover: making request\\n\"));\n\n    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\n    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));\n\n#if LWIP_NETIF_HOSTNAME\n    if (netif->hostname != NULL) {\n      const char *p = (const char*)netif->hostname;\n      u8_t namelen = (u8_t)os_strlen(p);\n      if (namelen > 0) {\n        LWIP_ASSERT(\"DHCP: hostname is too long!\", namelen < 255);\n        dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);\n        while (*p) {\n          dhcp_option_byte(dhcp, *p++);\n        }\n      }\n    }\n#endif /* LWIP_NETIF_HOSTNAME */\n    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 12/*num options*/);\n    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);\n    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);\n    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);\n    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);\n    dhcp_option_byte(dhcp, DHCP_OPTION_DOMAIN_NAME);\n            dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINS);\n            dhcp_option_byte(dhcp, DHCP_OPTION_NB_TINT);\n            dhcp_option_byte(dhcp, DHCP_OPTION_NB_TIS);\n            dhcp_option_byte(dhcp, DHCP_OPTION_PRD);\n            dhcp_option_byte(dhcp, DHCP_OPTION_STATIC_ROUTER);\n            dhcp_option_byte(dhcp, DHCP_OPTION_CLASSLESS_STATIC_ROUTER);\n            dhcp_option_byte(dhcp, DHCP_OPTION_VSN);\n\n    dhcp_option_trailer(dhcp);\n\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_discover: realloc()ing\\n\"));\n    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\n\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\\n\"));\n    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_discover: deleting()ing\\n\"));\n    dhcp_delete_msg(dhcp);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_discover: SELECTING\\n\"));\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"dhcp_discover: could not allocate DHCP request\\n\"));\n  }\n  dhcp->tries++;\n#if LWIP_DHCP_AUTOIP_COOP\n  if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {\n    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;\n    autoip_start(netif);\n  }\n#endif /* LWIP_DHCP_AUTOIP_COOP */\n  msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;\n  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_discover(): set request timeout %\"U16_F\" msecs\\n\", msecs));\n  return result;\n}\n\n\n/**\n * Bind the interface to the offered IP address.\n *\n * @param netif network interface to bind to the offered address\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_bind(struct netif *netif)\n{\n  u32_t timeout;\n  struct dhcp *dhcp;\n  ip_addr_t sn_mask, gw_addr;\n  LWIP_ERROR(\"dhcp_bind: netif != NULL\", (netif != NULL), return;);\n  dhcp = netif->dhcp;\n  LWIP_ERROR(\"dhcp_bind: dhcp != NULL\", (dhcp != NULL), return;);\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_bind(netif=%p) %c%c%\"U16_F\"\\n\", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\n\n  /* temporary DHCP lease? */\n  if (dhcp->offered_t1_renew != 0xffffffffUL) {\n    /* set renewal period timer */\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_bind(): t1 renewal timer %\"U32_F\" secs\\n\", dhcp->offered_t1_renew));\n    timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;\n    if(timeout > 0xffff) {\n      timeout = 0xffff;\n    }\n    dhcp->t1_timeout = (u16_t)timeout;\n    if (dhcp->t1_timeout == 0) {\n      dhcp->t1_timeout = 1;\n    }\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_bind(): set request timeout %\"U32_F\" msecs\\n\", dhcp->offered_t1_renew*1000));\n  }\n  /* set renewal period timer */\n  if (dhcp->offered_t2_rebind != 0xffffffffUL) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_bind(): t2 rebind timer %\"U32_F\" secs\\n\", dhcp->offered_t2_rebind));\n    timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;\n    if(timeout > 0xffff) {\n      timeout = 0xffff;\n    }\n    dhcp->t2_timeout = (u16_t)timeout;\n    if (dhcp->t2_timeout == 0) {\n      dhcp->t2_timeout = 1;\n    }\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_bind(): set request timeout %\"U32_F\" msecs\\n\", dhcp->offered_t2_rebind*1000));\n  }\n\n  /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. modify by ives at 2014.4.22*/\n  if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) {\n    dhcp->t1_timeout = 0;\n  }\n\n  if (dhcp->subnet_mask_given) {\n    /* copy offered network mask */\n    ip_addr_copy(sn_mask, dhcp->offered_sn_mask);\n  } else {\n    /* subnet mask not given, choose a safe subnet mask given the network class */\n    u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr);\n    if (first_octet <= 127) {\n      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000));\n    } else if (first_octet >= 192) {\n      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00));\n    } else {\n      ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000));\n    }\n  }\n\n  ip_addr_copy(gw_addr, dhcp->offered_gw_addr);\n  /* gateway address not given? */\n  if (ip_addr_isany(&gw_addr)) {\n    /* copy network address */\n    ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask);\n    /* use first host address on network as gateway */\n    ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001));\n  }\n\n#if LWIP_DHCP_AUTOIP_COOP\n  if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {\n    autoip_stop(netif);\n    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;\n  }\n#endif /* LWIP_DHCP_AUTOIP_COOP */\n\n  // wjg:back up old ip/netmask/gw\n  ip_addr_t ip, mask, gw;\n  ip = netif->ip_addr;\n  mask = netif->netmask;\n  gw = netif->gw;\n\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, (\"dhcp_bind(): IP: 0x%08\"X32_F\"\\n\",\n    ip4_addr_get_u32(&dhcp->offered_ip_addr)));\n  netif_set_ipaddr(netif, &dhcp->offered_ip_addr);\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, (\"dhcp_bind(): SN: 0x%08\"X32_F\"\\n\",\n    ip4_addr_get_u32(&sn_mask)));\n  netif_set_netmask(netif, &sn_mask);\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, (\"dhcp_bind(): GW: 0x%08\"X32_F\"\\n\",\n    ip4_addr_get_u32(&gw_addr)));\n  netif_set_gw(netif, &gw_addr);\n\n  /* bring the interface up */\n  netif_set_up(netif);\n\n  // wjg: use old ip/mask/gw to check whether ip/mask/gw changed\n  system_station_got_ip_set(&ip, &mask, &gw);\n\n  /* netif is now bound to DHCP leased address */\n  dhcp_set_state(dhcp, DHCP_BOUND);\n}\n\n/**\n * Renew an existing DHCP lease at the involved DHCP server.\n *\n * @param netif network interface which must renew its lease\n */\nerr_t ICACHE_FLASH_ATTR\ndhcp_renew(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  err_t result;\n  u16_t msecs;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_renew()\\n\"));\n  dhcp_set_state(dhcp, DHCP_RENEWING);\n\n  /* create and initialize the DHCP message header */\n  result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);\n  if (result == ERR_OK) {\n    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\n    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));\n\n#if LWIP_NETIF_HOSTNAME\n    if (netif->hostname != NULL) {\n      const char *p = (const char*)netif->hostname;\n      u8_t namelen = (u8_t)os_strlen(p);\n      if (namelen > 0) {\n        LWIP_ASSERT(\"DHCP: hostname is too long!\", namelen < 255);\n        dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);\n        while (*p) {\n          dhcp_option_byte(dhcp, *p++);\n        }\n      }\n    }\n#endif /* LWIP_NETIF_HOSTNAME */\n\n#if 0\n    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\n    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\n#endif\n\n#if 0\n    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\n    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\n#endif\n    /* append DHCP message trailer */\n    dhcp_option_trailer(dhcp);\n\n    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\n\n    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);\n    dhcp_delete_msg(dhcp);\n\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_renew: RENEWING\\n\"));\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"dhcp_renew: could not allocate DHCP request\\n\"));\n  }\n  dhcp->tries++;\n  /* back-off on retries, but to a maximum of 20 seconds */\n  msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;\n  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_renew(): set request timeout %\"U16_F\" msecs\\n\", msecs));\n  return result;\n}\n\n/**\n * Rebind with a DHCP server for an existing DHCP lease.\n *\n * @param netif network interface which must rebind with a DHCP server\n */\nstatic err_t ICACHE_FLASH_ATTR\ndhcp_rebind(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  err_t result;\n  u16_t msecs;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_rebind()\\n\"));\n  dhcp_set_state(dhcp, DHCP_REBINDING);\n\n  /* create and initialize the DHCP message header */\n  result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);\n  if (result == ERR_OK) {\n    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\n    dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));\n\n#if LWIP_NETIF_HOSTNAME\n    if (netif->hostname != NULL) {\n      const char *p = (const char*)netif->hostname;\n      u8_t namelen = (u8_t)os_strlen(p);\n      if (namelen > 0) {\n        LWIP_ASSERT(\"DHCP: hostname is too long!\", namelen < 255);\n        dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen);\n        while (*p) {\n          dhcp_option_byte(dhcp, *p++);\n        }\n      }\n    }\n#endif /* LWIP_NETIF_HOSTNAME */\n\n#if 0\n    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\n    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\n\n    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\n    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\n#endif\n\n    dhcp_option_trailer(dhcp);\n\n    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\n\n    /* broadcast to server */\n    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\n    dhcp_delete_msg(dhcp);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_rebind: REBINDING\\n\"));\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"dhcp_rebind: could not allocate DHCP request\\n\"));\n  }\n  dhcp->tries++;\n  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\n  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_rebind(): set request timeout %\"U16_F\" msecs\\n\", msecs));\n  return result;\n}\n\n/**\n * Enter REBOOTING state to verify an existing lease\n *\n * @param netif network interface which must reboot\n */\nstatic err_t ICACHE_FLASH_ATTR\ndhcp_reboot(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  err_t result;\n  u16_t msecs;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_reboot()\\n\"));\n  dhcp_set_state(dhcp, DHCP_REBOOTING);\n\n  /* create and initialize the DHCP message header */\n  result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST);\n  if (result == ERR_OK) {\n    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\n    dhcp_option_short(dhcp, 576);\n\n    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\n    dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr)));\n\n    dhcp_option_trailer(dhcp);\n\n    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\n\n    /* broadcast to server */\n    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\n    dhcp_delete_msg(dhcp);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_reboot: REBOOTING\\n\"));\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"dhcp_reboot: could not allocate DHCP request\\n\"));\n  }\n  dhcp->tries++;\n  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\n  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_reboot(): set request timeout %\"U16_F\" msecs\\n\", msecs));\n  return result;\n}\n\n\n/**\n * Release a DHCP lease.\n *\n * @param netif network interface which must release its lease\n */\nerr_t ICACHE_FLASH_ATTR\ndhcp_release(struct netif *netif)\n{\n  struct dhcp *dhcp = netif->dhcp;\n  err_t result;\n  u16_t msecs;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_release()\\n\"));\n  if (dhcp == NULL) {\n    return ERR_ARG;\n  }\n\n  /* idle DHCP client */\n  dhcp_set_state(dhcp, DHCP_OFF);\n  /* clean old DHCP offer */\n  ip_addr_set_zero(&dhcp->server_ip_addr);\n  ip_addr_set_zero(&dhcp->offered_ip_addr);\n  ip_addr_set_zero(&dhcp->offered_sn_mask);\n  ip_addr_set_zero(&dhcp->offered_gw_addr);\n#if LWIP_DHCP_BOOTP_FILE\n  ip_addr_set_zero(&dhcp->offered_si_addr);\n#endif /* LWIP_DHCP_BOOTP_FILE */\n  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;\n  \n  /* create and initialize the DHCP message header */\n  result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE);\n  if (result == ERR_OK) {\n    dhcp_option_trailer(dhcp);\n\n    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\n\n    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);\n    dhcp_delete_msg(dhcp);\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_release: RELEASED, DHCP_OFF\\n\"));\n  } else {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"dhcp_release: could not allocate DHCP request\\n\"));\n  }\n  dhcp->tries++;\n  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\n  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"dhcp_release(): set request timeout %\"U16_F\" msecs\\n\", msecs));\n  /* bring the interface down */\n  netif_set_down(netif);\n  /* remove IP address from interface */\n  netif_set_ipaddr(netif, IP_ADDR_ANY);\n  netif_set_gw(netif, IP_ADDR_ANY);\n  netif_set_netmask(netif, IP_ADDR_ANY);\n  \n  return result;\n}\n\n/**\n * Remove the DHCP client from the interface.\n *\n * @param netif The network interface to stop DHCP on\n */\nvoid ICACHE_FLASH_ATTR\ndhcp_stop(struct netif *netif)\n{\n  struct dhcp *dhcp;\n  LWIP_ERROR(\"dhcp_stop: netif != NULL\", (netif != NULL), return;);\n  dhcp = netif->dhcp;\n  /* Remove the flag that says this netif is handled by DHCP. */\n  netif->flags &= ~NETIF_FLAG_DHCP;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_stop()\\n\"));\n  /* netif is DHCP configured? */\n  if (dhcp != NULL) {\n#if LWIP_DHCP_AUTOIP_COOP\n    if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {\n      autoip_stop(netif);\n      dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;\n    }\n#endif /* LWIP_DHCP_AUTOIP_COOP */\n\n    if (dhcp->pcb != NULL) {\n      udp_remove(dhcp->pcb);\n      dhcp->pcb = NULL;\n    }\n    LWIP_ASSERT(\"reply wasn't freed\", dhcp->msg_in == NULL);\n    dhcp_set_state(dhcp, DHCP_OFF);\n  }\n}\n\n/*\n * Set the DHCP state of a DHCP client.\n *\n * If the state changed, reset the number of tries.\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_set_state(struct dhcp *dhcp, u8_t new_state)\n{\n  if (new_state != dhcp->state) {\n    dhcp->state = new_state;\n    dhcp->tries = 0;\n    dhcp->request_timeout = 0;\n  }\n}\n\n/*\n * Concatenate an option type and length field to the outgoing\n * DHCP message.\n *\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)\n{\n  LWIP_ASSERT(\"dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN\", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);\n  dhcp->msg_out->options[dhcp->options_out_len++] = option_type;\n  dhcp->msg_out->options[dhcp->options_out_len++] = option_len;\n}\n/*\n * Concatenate a single byte to the outgoing DHCP message.\n *\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_option_byte(struct dhcp *dhcp, u8_t value)\n{\n  LWIP_ASSERT(\"dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN\", dhcp->options_out_len < DHCP_OPTIONS_LEN);\n  dhcp->msg_out->options[dhcp->options_out_len++] = value;\n}\n\nstatic void ICACHE_FLASH_ATTR\ndhcp_option_short(struct dhcp *dhcp, u16_t value)\n{\n  LWIP_ASSERT(\"dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN\", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN);\n  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8);\n  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU);\n}\n\nstatic void ICACHE_FLASH_ATTR\ndhcp_option_long(struct dhcp *dhcp, u32_t value)\n{\n  LWIP_ASSERT(\"dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN\", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN);\n  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);\n  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);\n  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);\n  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));\n}\n\n/**\n * Extract the DHCP message and the DHCP options.\n *\n * Extract the DHCP message and the DHCP options, each into a contiguous\n * piece of memory. As a DHCP message is variable sized by its options,\n * and also allows overriding some fields for options, the easy approach\n * is to first unfold the options into a conitguous piece of memory, and\n * use that further on.\n *\n */\nstatic err_t ICACHE_FLASH_ATTR\ndhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p)\n{\n  u8_t *options;\n  u16_t offset;\n  u16_t offset_max;\n  u16_t options_idx;\n  u16_t options_idx_max;\n  struct pbuf *q;\n  int parse_file_as_options = 0;\n  int parse_sname_as_options = 0;\n\n  /* clear received options */\n  dhcp_clear_all_options(dhcp);\n  /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */\n  if (p->len < DHCP_SNAME_OFS) {\n    return ERR_BUF;\n  }\n  dhcp->msg_in = (struct dhcp_msg *)p->payload;\n#if LWIP_DHCP_BOOTP_FILE\n  /* clear boot file name */\n  dhcp->boot_file_name[0] = 0;\n#endif /* LWIP_DHCP_BOOTP_FILE */\n\n  /* parse options */\n\n  /* start with options field */\n  options_idx = DHCP_OPTIONS_OFS;\n  /* parse options to the end of the received packet */\n  options_idx_max = p->tot_len;\nagain:\n  q = p;\n  while((q != NULL) && (options_idx >= q->len)) {\n    options_idx -= q->len;\n    options_idx_max -= q->len;\n    q = q->next;\n  }\n  if (q == NULL) {\n    return ERR_BUF;\n  }\n  offset = options_idx;\n  offset_max = options_idx_max;\n  options = (u8_t*)q->payload;\n  /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */\n  while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) {\n    u8_t op = options[offset];\n    u8_t len;\n    u8_t decode_len = 0;\n    int decode_idx = -1;\n    u16_t val_offset = offset + 2;\n    /* len byte might be in the next pbuf */\n    if (offset + 1 < q->len) {\n      len = options[offset + 1];\n    } else {\n      len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0);\n    }\n    /* LWIP_DEBUGF(DHCP_DEBUG, (\"msg_offset=%\"U16_F\", q->len=%\"U16_F, msg_offset, q->len)); */\n    decode_len = len;\n    switch(op) {\n      /* case(DHCP_OPTION_END): handled above */\n      case(DHCP_OPTION_PAD):\n        /* special option: no len encoded */\n        decode_len = len = 0;\n        /* will be increased below */\n        offset--;\n        break;\n      case(DHCP_OPTION_SUBNET_MASK):\n        LWIP_ASSERT(\"len == 4\", len == 4);\n        decode_idx = DHCP_OPTION_IDX_SUBNET_MASK;\n        break;\n      case(DHCP_OPTION_ROUTER):\n        decode_len = 4; /* only copy the first given router */\n        LWIP_ASSERT(\"len >= decode_len\", len >= decode_len);\n        decode_idx = DHCP_OPTION_IDX_ROUTER;\n        break;\n      case(DHCP_OPTION_DNS_SERVER):\n        /* special case: there might be more than one server */\n        LWIP_ASSERT(\"len % 4 == 0\", len % 4 == 0);\n        /* limit number of DNS servers */\n        decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS);\n        LWIP_ASSERT(\"len >= decode_len\", len >= decode_len);\n        decode_idx = DHCP_OPTION_IDX_DNS_SERVER;\n        break;\n      case(DHCP_OPTION_LEASE_TIME):\n        LWIP_ASSERT(\"len == 4\", len == 4);\n        decode_idx = DHCP_OPTION_IDX_LEASE_TIME;\n        break;\n      case(DHCP_OPTION_OVERLOAD):\n        LWIP_ASSERT(\"len == 1\", len == 1);\n        decode_idx = DHCP_OPTION_IDX_OVERLOAD;\n        break;\n      case(DHCP_OPTION_MESSAGE_TYPE):\n        LWIP_ASSERT(\"len == 1\", len == 1);\n        decode_idx = DHCP_OPTION_IDX_MSG_TYPE;\n        break;\n      case(DHCP_OPTION_SERVER_ID):\n        LWIP_ASSERT(\"len == 4\", len == 4);\n        decode_idx = DHCP_OPTION_IDX_SERVER_ID;\n        break;\n      case(DHCP_OPTION_T1):\n        LWIP_ASSERT(\"len == 4\", len == 4);\n        decode_idx = DHCP_OPTION_IDX_T1;\n        break;\n      case(DHCP_OPTION_T2):\n        LWIP_ASSERT(\"len == 4\", len == 4);\n        decode_idx = DHCP_OPTION_IDX_T2;\n        break;\n      default:\n        decode_len = 0;\n        LWIP_DEBUGF(DHCP_DEBUG, (\"skipping option %\"U16_F\" in options\\n\", op));\n        break;\n    }\n    offset += len + 2;\n    if (decode_len > 0) {\n      u32_t value = 0;\n      u16_t copy_len;\ndecode_next:\n      LWIP_ASSERT(\"check decode_idx\", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX);\n      LWIP_ASSERT(\"option already decoded\", !dhcp_option_given(dhcp, decode_idx));\n      copy_len = LWIP_MIN(decode_len, 4);\n      pbuf_copy_partial(q, &value, copy_len, val_offset);\n      if (decode_len > 4) {\n        /* decode more than one u32_t */\n        LWIP_ASSERT(\"decode_len % 4 == 0\", decode_len % 4 == 0);\n        dhcp_got_option(dhcp, decode_idx);\n        dhcp_set_option_value(dhcp, decode_idx, htonl(value));\n        decode_len -= 4;\n        val_offset += 4;\n        decode_idx++;\n        goto decode_next;\n      } else if (decode_len == 4) {\n        value = ntohl(value);\n      } else {\n        LWIP_ASSERT(\"invalid decode_len\", decode_len == 1);\n        value = ((u8_t*)&value)[0];\n      }\n      dhcp_got_option(dhcp, decode_idx);\n      dhcp_set_option_value(dhcp, decode_idx, value);\n    }\n    if (offset >= q->len) {\n      offset -= q->len;\n      offset_max -= q->len;\n      if ((offset < offset_max) && offset_max) { //modify by ives at 2014.4.22\n        q = q->next;\n        LWIP_ASSERT(\"next pbuf was null\", q);\n        options = (u8_t*)q->payload;\n      } else {\n        /* We've run out of bytes, probably no end marker. Don't proceed. */\n        break;\n      }\n    }\n  }\n  /* is this an overloaded message? */\n  if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) {\n    u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD);\n    dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD);\n    if (overload == DHCP_OVERLOAD_FILE) {\n      parse_file_as_options = 1;\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"overloaded file field\\n\"));\n    } else if (overload == DHCP_OVERLOAD_SNAME) {\n      parse_sname_as_options = 1;\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"overloaded sname field\\n\"));\n    } else if (overload == DHCP_OVERLOAD_SNAME_FILE) {\n      parse_sname_as_options = 1;\n      parse_file_as_options = 1;\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"overloaded sname and file field\\n\"));\n    } else {\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"invalid overload option: %d\\n\", (int)overload));\n    }\n#if LWIP_DHCP_BOOTP_FILE\n    if (!parse_file_as_options) {\n      /* only do this for ACK messages */\n      if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) &&\n        (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK))\n      /* copy bootp file name, don't care for sname (server hostname) */\n      pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS);\n      /* make sure the string is really NULL-terminated */\n      dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0;\n    }\n#endif /* LWIP_DHCP_BOOTP_FILE */\n  }\n  if (parse_file_as_options) {\n    /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */\n    parse_file_as_options = 0;\n    options_idx = DHCP_FILE_OFS;\n    options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN;\n    goto again;\n  } else if (parse_sname_as_options) {\n    parse_sname_as_options = 0;\n    options_idx = DHCP_SNAME_OFS;\n    options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN;\n    goto again;\n  }\n  return ERR_OK;\n}\n\n/**\n * If an incoming DHCP message is in response to us, then trigger the state machine\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)\n{\n  struct netif *netif = (struct netif *)arg;\n  struct dhcp *dhcp = netif->dhcp;\n  struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;\n  u8_t msg_type;\n  u8_t i;\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"dhcp_recv(pbuf = %p) from DHCP server %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\" port %\"U16_F\"\\n\", (void*)p,\n    ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port));\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"pbuf->len = %\"U16_F\"\\n\", p->len));\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"pbuf->tot_len = %\"U16_F\"\\n\", p->tot_len));\n  /* prevent warnings about unused arguments */\n  LWIP_UNUSED_ARG(pcb);\n  LWIP_UNUSED_ARG(addr);\n  LWIP_UNUSED_ARG(port);\n\n  LWIP_ASSERT(\"reply wasn't freed\", dhcp->msg_in == NULL);\n\n  if (p->len < DHCP_MIN_REPLY_LEN) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, (\"DHCP reply message or pbuf too short\\n\"));\n    goto free_pbuf_and_return;\n  }\n\n  if (reply_msg->op != DHCP_BOOTREPLY) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, (\"not a DHCP reply message, but type %\"U16_F\"\\n\", (u16_t)reply_msg->op));\n    goto free_pbuf_and_return;\n  }\n  /* iterate through hardware address and match against DHCP message */\n  for (i = 0; i < netif->hwaddr_len; i++) {\n    if (netif->hwaddr[i] != reply_msg->chaddr[i]) {\n      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,\n        (\"netif->hwaddr[%\"U16_F\"]==%02\"X16_F\" != reply_msg->chaddr[%\"U16_F\"]==%02\"X16_F\"\\n\",\n        (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));\n      goto free_pbuf_and_return;\n    }\n  }\n  /* match transaction ID against what we expected */\n  if (ntohl(reply_msg->xid) != dhcp->xid) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,\n      (\"transaction id mismatch reply_msg->xid(%\"X32_F\")!=dhcp->xid(%\"X32_F\")\\n\",ntohl(reply_msg->xid),dhcp->xid));\n    goto free_pbuf_and_return;\n  }\n  /* option fields could be unfold? */\n  if (dhcp_parse_reply(dhcp, p) != ERR_OK) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,\n      (\"problem unfolding DHCP message - too short on memory?\\n\"));\n    goto free_pbuf_and_return;\n  }\n\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"searching DHCP_OPTION_MESSAGE_TYPE\\n\"));\n  /* obtain pointer to DHCP message type */\n  if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, (\"DHCP_OPTION_MESSAGE_TYPE option not found\\n\"));\n    goto free_pbuf_and_return;\n  }\n\n  /* read DHCP message type */\n  msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE);\n  /* message type is DHCP ACK? */\n  if (msg_type == DHCP_ACK) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"DHCP_ACK received\\n\"));\n    /* in requesting state? */\n    if (dhcp->state == DHCP_REQUESTING) {\n      dhcp_handle_ack(netif);\n#if DHCP_DOES_ARP_CHECK\n      /* check if the acknowledged lease address is already in use */\n      dhcp_check(netif);\n#else\n      /* bind interface to the acknowledged lease address */\n      dhcp_bind(netif);\n#endif\n    }\n    /* already bound to the given lease address? */\n    else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {\n      dhcp_bind(netif);\n    }\n  }\n  /* received a DHCP_NAK in appropriate state? */\n  else if ((msg_type == DHCP_NAK) &&\n    ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||\n     (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"DHCP_NAK received\\n\"));\n    dhcp_handle_nak(netif);\n  }\n  /* received a DHCP_OFFER in DHCP_SELECTING state? */\n  else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, (\"DHCP_OFFER received in DHCP_SELECTING state\\n\"));\n    dhcp->request_timeout = 0;\n    /* remember offered lease */\n    dhcp_handle_offer(netif);\n  }\nfree_pbuf_and_return:\n  dhcp->msg_in = NULL;\n  pbuf_free(p);\n}\n\n/**\n * Create a DHCP request, fill in common headers\n *\n * @param netif the netif under DHCP control\n * @param dhcp dhcp control struct\n * @param message_type message type of the request\n */\nstatic err_t ICACHE_FLASH_ATTR\ndhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type)\n{\n  u16_t i;\n#ifndef DHCP_GLOBAL_XID\n  /** default global transaction identifier starting value (easy to match\n   *  with a packet analyser). We simply increment for each new request.\n   *  Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one\n   *  at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */\n  static u32_t xid = 0xABCD0000;\n#else\n  static u32_t xid;\n  static u8_t xid_initialised = 0;\n  if (!xid_initialised) {\n    xid = DHCP_GLOBAL_XID;\n    xid_initialised = !xid_initialised;\n  }\n#endif\n  LWIP_ERROR(\"dhcp_create_msg: netif != NULL\", (netif != NULL), return ERR_ARG;);\n  LWIP_ERROR(\"dhcp_create_msg: dhcp != NULL\", (dhcp != NULL), return ERR_VAL;);\n  LWIP_ASSERT(\"dhcp_create_msg: dhcp->p_out == NULL\", dhcp->p_out == NULL);\n  LWIP_ASSERT(\"dhcp_create_msg: dhcp->msg_out == NULL\", dhcp->msg_out == NULL);\n  dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);\n  if (dhcp->p_out == NULL) {\n    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,\n      (\"dhcp_create_msg(): could not allocate pbuf\\n\"));\n    return ERR_MEM;\n  }\n  LWIP_ASSERT(\"dhcp_create_msg: check that first pbuf can hold struct dhcp_msg\",\n           (dhcp->p_out->len >= sizeof(struct dhcp_msg)));\n\n  /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER modify by ives at 2014.4.22*/\n  if (message_type != DHCP_REQUEST) {\n  \t/* reuse transaction identifier in retransmissions */\n  \tif (dhcp->tries == 0) {\n      \txid++;\n  \t}\n  \tdhcp->xid = xid;\n  }\n  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,\n              (\"transaction id xid(%\"X32_F\")\\n\", xid));\n\n  dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;\n\n  dhcp->msg_out->op = DHCP_BOOTREQUEST;\n  /* TODO: make link layer independent */\n  dhcp->msg_out->htype = DHCP_HTYPE_ETH;\n  dhcp->msg_out->hlen = netif->hwaddr_len;\n  dhcp->msg_out->hops = 0;\n  dhcp->msg_out->xid = htonl(dhcp->xid);\n  dhcp->msg_out->secs = 0;\n  /* we don't need the broadcast flag since we can receive unicast traffic\n     before being fully configured! */\n  dhcp->msg_out->flags = 0;\n  ip_addr_set_zero(&dhcp->msg_out->ciaddr);\n  /* set ciaddr to netif->ip_addr based on message_type and state */\n  if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) ||\n      ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */\n       ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) {\n    ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr);\n  }\n  ip_addr_set_zero(&dhcp->msg_out->yiaddr);\n  ip_addr_set_zero(&dhcp->msg_out->siaddr);\n  ip_addr_set_zero(&dhcp->msg_out->giaddr);\n  for (i = 0; i < DHCP_CHADDR_LEN; i++) {\n    /* copy netif hardware address, pad with zeroes */\n    dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN) ? netif->hwaddr[i] : 0/* pad byte*/;\n  }\n  for (i = 0; i < DHCP_SNAME_LEN; i++) {\n    dhcp->msg_out->sname[i] = 0;\n  }\n  for (i = 0; i < DHCP_FILE_LEN; i++) {\n    dhcp->msg_out->file[i] = 0;\n  }\n  dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);\n  dhcp->options_out_len = 0;\n  /* fill options field with an incrementing array (for debugging purposes) */\n  for (i = 0; i < DHCP_OPTIONS_LEN; i++) {\n    dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */\n  }\n  /* Add option MESSAGE_TYPE */\n  dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\n  dhcp_option_byte(dhcp, message_type);\n  return ERR_OK;\n}\n\n/**\n * Free previously allocated memory used to send a DHCP request.\n *\n * @param dhcp the dhcp struct to free the request from\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_delete_msg(struct dhcp *dhcp)\n{\n  LWIP_ERROR(\"dhcp_delete_msg: dhcp != NULL\", (dhcp != NULL), return;);\n  LWIP_ASSERT(\"dhcp_delete_msg: dhcp->p_out != NULL\", dhcp->p_out != NULL);\n  LWIP_ASSERT(\"dhcp_delete_msg: dhcp->msg_out != NULL\", dhcp->msg_out != NULL);\n  if (dhcp->p_out != NULL) {\n    pbuf_free(dhcp->p_out);\n  }\n  dhcp->p_out = NULL;\n  dhcp->msg_out = NULL;\n}\n\n/**\n * Add a DHCP message trailer\n *\n * Adds the END option to the DHCP message, and if\n * necessary, up to three padding bytes.\n *\n * @param dhcp DHCP state structure\n */\nstatic void ICACHE_FLASH_ATTR\ndhcp_option_trailer(struct dhcp *dhcp)\n{\n  LWIP_ERROR(\"dhcp_option_trailer: dhcp != NULL\", (dhcp != NULL), return;);\n  LWIP_ASSERT(\"dhcp_option_trailer: dhcp->msg_out != NULL\\n\", dhcp->msg_out != NULL);\n  LWIP_ASSERT(\"dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\\n\", dhcp->options_out_len < DHCP_OPTIONS_LEN);\n  dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;\n  /* packet is too small, or not 4 byte aligned? */\n  while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) &&\n         (dhcp->options_out_len < DHCP_OPTIONS_LEN)) {\n    /* LWIP_DEBUGF(DHCP_DEBUG,(\"dhcp_option_trailer:dhcp->options_out_len=%\"U16_F\", DHCP_OPTIONS_LEN=%\"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */\n    LWIP_ASSERT(\"dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\\n\", dhcp->options_out_len < DHCP_OPTIONS_LEN);\n    /* add a fill/padding byte */\n    dhcp->msg_out->options[dhcp->options_out_len++] = 0;\n  }\n}\n\n#endif /* LWIP_DHCP */\n"
  },
  {
    "path": "app/lwip/core/dns.c",
    "content": "/**\n * @file\n * DNS - host name to IP address resolver.\n *\n */\n\n/**\n\n * This file implements a DNS host name to IP address resolver.\n\n * Port to lwIP from uIP\n * by Jim Pettinato April 2007\n\n * uIP version Copyright (c) 2002-2003, Adam Dunkels.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote\n *    products derived from this software without specific prior\n *    written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\n * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n *\n * DNS.C\n *\n * The lwIP DNS resolver functions are used to lookup a host name and\n * map it to a numerical IP address. It maintains a list of resolved\n * hostnames that can be queried with the dns_lookup() function.\n * New hostnames can be resolved using the dns_query() function.\n *\n * The lwIP version of the resolver also adds a non-blocking version of\n * gethostbyname() that will work with a raw API application. This function\n * checks for an IP address string first and converts it if it is valid.\n * gethostbyname() then does a dns_lookup() to see if the name is \n * already in the table. If so, the IP is returned. If not, a query is \n * issued and the function returns with a ERR_INPROGRESS status. The app\n * using the dns client must then go into a waiting state.\n *\n * Once a hostname has been resolved (or found to be non-existent),\n * the resolver code calls a specified callback function (which \n * must be implemented by the module that uses the resolver).\n */\n\n/*-----------------------------------------------------------------------------\n * RFC 1035 - Domain names - implementation and specification\n * RFC 2181 - Clarifications to the DNS Specification\n *----------------------------------------------------------------------------*/\n\n/** @todo: define good default values (rfc compliance) */\n/** @todo: improve answer parsing, more checkings... */\n/** @todo: check RFC1035 - 7.3. Processing responses */\n\n/*-----------------------------------------------------------------------------\n * Includes\n *----------------------------------------------------------------------------*/\n\n#include \"lwip/opt.h\"\n\n#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/udp.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/dns.h\"\n\n#include <string.h>\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/** DNS server IP address */\n#ifndef DNS_SERVER_ADDRESS\n#define DNS_SERVER_ADDRESS(ipaddr)        (ip4_addr_set_u32(ipaddr, 0xDEDE43D0)) /* resolver1.opendns.com(208.67.222.222) */\n#endif\n\n/** DNS server port address */\n#ifndef DNS_SERVER_PORT\n#define DNS_SERVER_PORT           53\n#endif\n\n/** DNS maximum number of retries when asking for a name, before \"timeout\". */\n#ifndef DNS_MAX_RETRIES\n#define DNS_MAX_RETRIES           4\n#endif\n\n/** DNS resource record max. TTL (one week as default) */\n#ifndef DNS_MAX_TTL\n#define DNS_MAX_TTL               604800\n#endif\n\n/* DNS protocol flags */\n#define DNS_FLAG1_RESPONSE        0x80\n#define DNS_FLAG1_OPCODE_STATUS   0x10\n#define DNS_FLAG1_OPCODE_INVERSE  0x08\n#define DNS_FLAG1_OPCODE_STANDARD 0x00\n#define DNS_FLAG1_AUTHORATIVE     0x04\n#define DNS_FLAG1_TRUNC           0x02\n#define DNS_FLAG1_RD              0x01\n#define DNS_FLAG2_RA              0x80\n#define DNS_FLAG2_ERR_MASK        0x0f\n#define DNS_FLAG2_ERR_NONE        0x00\n#define DNS_FLAG2_ERR_NAME        0x03\n\n/* DNS protocol states */\n#define DNS_STATE_UNUSED          0\n#define DNS_STATE_NEW             1\n#define DNS_STATE_ASKING          2\n#define DNS_STATE_DONE            3\n\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\n/** DNS message header */\nstruct dns_hdr {\n  PACK_STRUCT_FIELD(u16_t id);\n  PACK_STRUCT_FIELD(u8_t flags1);\n  PACK_STRUCT_FIELD(u8_t flags2);\n  PACK_STRUCT_FIELD(u16_t numquestions);\n  PACK_STRUCT_FIELD(u16_t numanswers);\n  PACK_STRUCT_FIELD(u16_t numauthrr);\n  PACK_STRUCT_FIELD(u16_t numextrarr);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n#define SIZEOF_DNS_HDR 12\n\n/** DNS query message structure.\n    No packing needed: only used locally on the stack. */\nstruct dns_query {\n  /* DNS query record starts with either a domain name or a pointer\n     to a name already present somewhere in the packet. */\n  u16_t type;\n  u16_t cls;\n};\n#define SIZEOF_DNS_QUERY 4\n\n/** DNS answer message structure.\n    No packing needed: only used locally on the stack. */\nstruct dns_answer {\n  /* DNS answer record starts with either a domain name or a pointer\n     to a name already present somewhere in the packet. */\n  u16_t type;\n  u16_t cls;\n  u32_t ttl;\n  u16_t len;\n};\n#define SIZEOF_DNS_ANSWER 10\n\n/** DNS table entry */\nstruct dns_table_entry {\n  u8_t  state;\n  u8_t  numdns;\n  u8_t  tmr;\n  u8_t  retries;\n  u8_t  seqno;\n  u8_t  err;\n  u32_t ttl;\n  char name[DNS_MAX_NAME_LENGTH];\n  ip_addr_t ipaddr;\n  /* pointer to callback on DNS query done */\n  dns_found_callback found;\n  void *arg;\n};\n\n#if DNS_LOCAL_HOSTLIST\n\n#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC\n/** Local host-list. For hostnames in this list, no\n *  external name resolution is performed */\nstatic struct local_hostlist_entry *local_hostlist_dynamic;\n#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n\n/** Defining this allows the local_hostlist_static to be placed in a different\n * linker section (e.g. FLASH) */\n#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE\n#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static\n#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */\n/** Defining this allows the local_hostlist_static to be placed in a different\n * linker section (e.g. FLASH) */\n#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST\n#define DNS_LOCAL_HOSTLIST_STORAGE_POST\n#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */\nDNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]\n  DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;\n\n#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n\nstatic void dns_init_local();\n#endif /* DNS_LOCAL_HOSTLIST */\n\n\n/* forward declarations */\nstatic void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);\nstatic void dns_check_entries(void);\n\n/*-----------------------------------------------------------------------------\n * Globales\n *----------------------------------------------------------------------------*/\n\n/* DNS variables */\nstatic struct udp_pcb        *dns_pcb;\nstatic u8_t                   dns_seqno;\nstatic struct dns_table_entry dns_table[DNS_TABLE_SIZE];\nstatic ip_addr_t              dns_servers[DNS_MAX_SERVERS];\n/** Contiguous buffer for processing responses */\n//static u8_t                   dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];\nstatic u8_t*                  dns_payload;\nstatic u8_t\t\t\t\t\t  dns_random;\n/**\n * Initialize the resolver: set up the UDP pcb and configure the default server\n * (DNS_SERVER_ADDRESS).\n */\nvoid ICACHE_FLASH_ATTR\ndns_init()\n{\n  ip_addr_t dnsserver;\n\n//  dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);\n  \n  /* initialize default DNS server address */\n  DNS_SERVER_ADDRESS(&dnsserver);\n\n  LWIP_DEBUGF(DNS_DEBUG, (\"dns_init: initializing\\n\"));\n\n  /* if dns client not yet initialized... */\n  if (dns_pcb == NULL) {\n    dns_pcb = udp_new();\n\n    if (dns_pcb != NULL) {\n      /* initialize DNS table not needed (initialized to zero since it is a\n       * global variable) */\n      LWIP_ASSERT(\"For implicit initialization to work, DNS_STATE_UNUSED needs to be 0\",\n        DNS_STATE_UNUSED == 0);\n\n      /* initialize DNS client */\n      udp_bind(dns_pcb, IP_ADDR_ANY, 0);\n      udp_recv(dns_pcb, dns_recv, NULL);\n\n      /* initialize default DNS primary server */\n      dns_setserver(0, &dnsserver);\n    }\n  }\n#if DNS_LOCAL_HOSTLIST\n  dns_init_local();\n#endif\n}\n\n/**\n * Initialize one of the DNS servers.\n *\n * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS\n * @param dnsserver IP address of the DNS server to set\n */\nvoid ICACHE_FLASH_ATTR\ndns_setserver(u8_t numdns, ip_addr_t *dnsserver)\n{\n  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&\n      (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {\n    dns_servers[numdns] = (*dnsserver);\n  }\n}\n\n/**\n * Obtain one of the currently configured DNS server.\n *\n * @param numdns the index of the DNS server\n * @return IP address of the indexed DNS server or \"ip_addr_any\" if the DNS\n *         server has not been configured.\n */\nip_addr_t ICACHE_FLASH_ATTR\ndns_getserver(u8_t numdns)\n{\n  if (numdns < DNS_MAX_SERVERS) {\n    return dns_servers[numdns];\n  } else {\n    return *IP_ADDR_ANY;\n  }\n}\n\n/**\n * The DNS resolver client timer - handle retries and timeouts and should\n * be called every DNS_TMR_INTERVAL milliseconds (every second by default).\n */\nvoid ICACHE_FLASH_ATTR\ndns_tmr(void)\n{\n  if (dns_pcb != NULL) {\n    LWIP_DEBUGF(DNS_DEBUG, (\"dns_tmr: dns_check_entries\\n\"));\n    dns_check_entries();\n  }\n}\n\n#if DNS_LOCAL_HOSTLIST\nstatic void ICACHE_FLASH_ATTR\ndns_init_local()\n{\n#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)\n  int i;\n  struct local_hostlist_entry *entry;\n  /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */\n  struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;\n  size_t namelen;\n  for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {\n    struct local_hostlist_entry *init_entry = &local_hostlist_init[i];\n    LWIP_ASSERT(\"invalid host name (NULL)\", init_entry->name != NULL);\n    namelen = os_strlen(init_entry->name);\n    LWIP_ASSERT(\"namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN\", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);\n    entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);\n    LWIP_ASSERT(\"mem-error in dns_init_local\", entry != NULL);\n    if (entry != NULL) {\n      entry->name = (char*)entry + sizeof(struct local_hostlist_entry);\n      MEMCPY((char*)entry->name, init_entry->name, namelen);\n      ((char*)entry->name)[namelen] = 0;\n      entry->addr = init_entry->addr;\n      entry->next = local_hostlist_dynamic;\n      local_hostlist_dynamic = entry;\n    }\n  }\n#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */\n}\n\n/**\n * Scans the local host-list for a hostname.\n *\n * @param hostname Hostname to look for in the local host-list\n * @return The first IP address for the hostname in the local host-list or\n *         IPADDR_NONE if not found.\n */\nstatic u32_t ICACHE_FLASH_ATTR\ndns_lookup_local(const char *hostname)\n{\n#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC\n  struct local_hostlist_entry *entry = local_hostlist_dynamic;\n  while(entry != NULL) {\n    if(strcmp(entry->name, hostname) == 0) {\n      return ip4_addr_get_u32(&entry->addr);\n    }\n    entry = entry->next;\n  }\n#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n  int i;\n  for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {\n    if(strcmp(local_hostlist_static[i].name, hostname) == 0) {\n      return ip4_addr_get_u32(&local_hostlist_static[i].addr);\n    }\n  }\n#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */\n  return IPADDR_NONE;\n}\n\n#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC\n/** Remove all entries from the local host-list for a specific hostname\n * and/or IP addess\n *\n * @param hostname hostname for which entries shall be removed from the local\n *                 host-list\n * @param addr address for which entries shall be removed from the local host-list\n * @return the number of removed entries\n */\nint ICACHE_FLASH_ATTR\ndns_local_removehost(const char *hostname, const ip_addr_t *addr)\n{\n  int removed = 0;\n  struct local_hostlist_entry *entry = local_hostlist_dynamic;\n  struct local_hostlist_entry *last_entry = NULL;\n  while (entry != NULL) {\n    if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&\n        ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {\n      struct local_hostlist_entry *free_entry;\n      if (last_entry != NULL) {\n        last_entry->next = entry->next;\n      } else {\n        local_hostlist_dynamic = entry->next;\n      }\n      free_entry = entry;\n      entry = entry->next;\n      memp_free(MEMP_LOCALHOSTLIST, free_entry);\n      removed++;\n    } else {\n      last_entry = entry;\n      entry = entry->next;\n    }\n  }\n  return removed;\n}\n\n/**\n * Add a hostname/IP address pair to the local host-list.\n * Duplicates are not checked.\n *\n * @param hostname hostname of the new entry\n * @param addr IP address of the new entry\n * @return ERR_OK if succeeded or ERR_MEM on memory error\n */\nerr_t ICACHE_FLASH_ATTR\ndns_local_addhost(const char *hostname, const ip_addr_t *addr)\n{\n  struct local_hostlist_entry *entry;\n  size_t namelen;\n  LWIP_ASSERT(\"invalid host name (NULL)\", hostname != NULL);\n  namelen = os_strlen(hostname);\n  LWIP_ASSERT(\"namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN\", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);\n  entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);\n  if (entry == NULL) {\n    return ERR_MEM;\n  }\n  entry->name = (char*)entry + sizeof(struct local_hostlist_entry);\n  MEMCPY((char*)entry->name, hostname, namelen);\n  ((char*)entry->name)[namelen] = 0;\n  ip_addr_copy(entry->addr, *addr);\n  entry->next = local_hostlist_dynamic;\n  local_hostlist_dynamic = entry;\n  return ERR_OK;\n}\n#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/\n#endif /* DNS_LOCAL_HOSTLIST */\n\n/**\n * Look up a hostname in the array of known hostnames.\n *\n * @note This function only looks in the internal array of known\n * hostnames, it does not send out a query for the hostname if none\n * was found. The function dns_enqueue() can be used to send a query\n * for a hostname.\n *\n * @param name the hostname to look up\n * @return the hostname's IP address, as u32_t (instead of ip_addr_t to\n *         better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname\n *         was not found in the cached dns_table.\n */\nstatic u32_t ICACHE_FLASH_ATTR\ndns_lookup(const char *name)\n{\n  u8_t i;\n#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)\n  u32_t addr;\n#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */\n#if DNS_LOCAL_HOSTLIST\n  if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {\n    return addr;\n  }\n#endif /* DNS_LOCAL_HOSTLIST */\n#ifdef DNS_LOOKUP_LOCAL_EXTERN\n  if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {\n    return addr;\n  }\n#endif /* DNS_LOOKUP_LOCAL_EXTERN */\n\n  /* Walk through name list, return entry if found. If not, return NULL. */\n  for (i = 0; i < DNS_TABLE_SIZE; ++i) {\n    if ((dns_table[i].state == DNS_STATE_DONE) &&\n        (strcmp(name, dns_table[i].name) == 0)) {\n      LWIP_DEBUGF(DNS_DEBUG, (\"dns_lookup: \\\"%s\\\": found = \", name));\n      ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));\n      LWIP_DEBUGF(DNS_DEBUG, (\"\\n\"));\n      return ip4_addr_get_u32(&dns_table[i].ipaddr);\n    }\n  }\n\n  return IPADDR_NONE;\n}\n\n#if DNS_DOES_NAME_CHECK\n/**\n * Compare the \"dotted\" name \"query\" with the encoded name \"response\"\n * to make sure an answer from the DNS server matches the current dns_table\n * entry (otherwise, answers might arrive late for hostname not on the list\n * any more).\n *\n * @param query hostname (not encoded) from the dns_table\n * @param response encoded hostname in the DNS response\n * @return 0: names equal; 1: names differ\n */\nstatic u8_t ICACHE_FLASH_ATTR\ndns_compare_name(unsigned char *query, unsigned char *response)\n{\n  unsigned char n;\n\n  do {\n    n = *response++;\n    /** @see RFC 1035 - 4.1.4. Message compression */\n    if ((n & 0xc0) == 0xc0) {\n      /* Compressed name */\n      break;\n    } else {\n      /* Not compressed name */\n      while (n > 0) {\n        if ((*query) != (*response)) {\n          return 1;\n        }\n        ++response;\n        ++query;\n        --n;\n      };\n      ++query;\n    }\n  } while (*response != 0);\n\n  return 0;\n}\n#endif /* DNS_DOES_NAME_CHECK */\n\n/**\n * Walk through a compact encoded DNS name and return the end of the name.\n *\n * @param query encoded DNS name in the DNS server response\n * @return end of the name\n */\nstatic unsigned char * ICACHE_FLASH_ATTR\ndns_parse_name(unsigned char *query)\n{\n  unsigned char n;\n\n  do {\n    n = *query++;\n    /** @see RFC 1035 - 4.1.4. Message compression */\n    if ((n & 0xc0) == 0xc0) {\n      /* Compressed name */\n      break;\n    } else {\n      /* Not compressed name */\n      while (n > 0) {\n        ++query;\n        --n;\n      };\n    }\n  } while (*query != 0);\n\n  return query + 1;\n}\n\n/**\n * Send a DNS query packet.\n *\n * @param numdns index of the DNS server in the dns_servers table\n * @param name hostname to query\n * @param id index of the hostname in dns_table, used as transaction ID in the\n *        DNS query packet\n * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise\n */\nstatic err_t ICACHE_FLASH_ATTR\ndns_send(u8_t numdns, const char* name, u8_t id)\n{\n  err_t err;\n  struct dns_hdr *hdr;\n  struct dns_query qry;\n  struct pbuf *p;\n  char *query, *nptr;\n  const char *pHostname;\n  u8_t n;\n  dns_random = os_random()%250;\n  LWIP_DEBUGF(DNS_DEBUG, (\"dns_send: dns_servers[%\"U16_F\"] \\\"%s\\\": request\\n\",\n              (u16_t)(numdns), name));\n  LWIP_ASSERT(\"dns server out of array\", numdns < DNS_MAX_SERVERS);\n  LWIP_ASSERT(\"dns server has no IP address set\", !ip_addr_isany(&dns_servers[numdns]));\n\n  /* if here, we have either a new query or a retry on a previous query to process */\n  p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +\n                 SIZEOF_DNS_QUERY, PBUF_RAM);\n  if (p != NULL) {\n    LWIP_ASSERT(\"pbuf must be in one piece\", p->next == NULL);\n    /* fill dns header */\n    hdr = (struct dns_hdr*)p->payload;\n    os_memset(hdr, 0, SIZEOF_DNS_HDR);\n    hdr->id = htons(id + dns_random);\n    hdr->flags1 = DNS_FLAG1_RD;\n    hdr->numquestions = PP_HTONS(1);\n    query = (char*)hdr + SIZEOF_DNS_HDR;\n    pHostname = name;\n    --pHostname;\n\n    /* convert hostname into suitable query format. */\n    do {\n      ++pHostname;\n      nptr = query;\n      ++query;\n      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n        *query = *pHostname;\n        ++query;\n        ++n;\n      }\n      *nptr = n;\n    } while(*pHostname != 0);\n    *query++='\\0';\n\n    /* fill dns query */\n    qry.type = PP_HTONS(DNS_RRTYPE_A);\n    qry.cls = PP_HTONS(DNS_RRCLASS_IN);\n    SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);\n\n    /* resize pbuf to the exact dns query */\n    pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));\n\n    /* connect to the server for faster receiving */\n    udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);\n    /* send dns packet */\n    err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);\n\n    /* free pbuf */\n    pbuf_free(p);\n  } else {\n    err = ERR_MEM;\n  }\n\n  return err;\n}\n\n/**\n * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.\n * Check an entry in the dns_table:\n * - send out query for new entries\n * - retry old pending entries on timeout (also with different servers)\n * - remove completed entries from the table if their TTL has expired\n *\n * @param i index of the dns_table entry to check\n */\nstatic void ICACHE_FLASH_ATTR\ndns_check_entry(u8_t i)\n{\n  err_t err;\n  struct dns_table_entry *pEntry = &dns_table[i];\n\n  LWIP_ASSERT(\"array index out of bounds\", i < DNS_TABLE_SIZE);\n\n  switch(pEntry->state) {\n\n    case DNS_STATE_NEW: {\n      /* initialize new entry */\n      pEntry->state   = DNS_STATE_ASKING;\n      pEntry->numdns  = 0;\n      pEntry->tmr     = 1;\n      pEntry->retries = 0;\n      \n      /* send DNS packet for this entry */\n      err = dns_send(pEntry->numdns, pEntry->name, i);\n      if (err != ERR_OK) {\n        LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,\n                    (\"dns_send returned error: %s\\n\", lwip_strerr(err)));\n      }\n      break;\n    }\n\n    case DNS_STATE_ASKING: {\n      if (--pEntry->tmr == 0) {\n        if (++pEntry->retries == DNS_MAX_RETRIES) {\n          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {\n            /* change of server */\n            pEntry->numdns++;\n            pEntry->tmr     = 1;\n            pEntry->retries = 0;\n            break;\n          } else {\n            LWIP_DEBUGF(DNS_DEBUG, (\"dns_check_entry: \\\"%s\\\": timeout\\n\", pEntry->name));\n            /* call specified callback function if provided */\n            if (pEntry->found)\n              (*pEntry->found)(pEntry->name, NULL, pEntry->arg);\n            /* flush this entry */\n            pEntry->state   = DNS_STATE_UNUSED;\n            pEntry->found   = NULL;\n            break;\n          }\n        }\n\n        /* wait longer for the next retry */\n        pEntry->tmr = pEntry->retries;\n\n        /* send DNS packet for this entry */\n        err = dns_send(pEntry->numdns, pEntry->name, i);\n        if (err != ERR_OK) {\n          LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,\n                      (\"dns_send returned error: %s\\n\", lwip_strerr(err)));\n        }\n      }\n      break;\n    }\n\n    case DNS_STATE_DONE: {\n      /* if the time to live is nul */\n      if (--pEntry->ttl == 0) {\n        LWIP_DEBUGF(DNS_DEBUG, (\"dns_check_entry: \\\"%s\\\": flush\\n\", pEntry->name));\n        /* flush this entry */\n        pEntry->state = DNS_STATE_UNUSED;\n        pEntry->found = NULL;\n      }\n      break;\n    }\n    case DNS_STATE_UNUSED:\n      /* nothing to do */\n      break;\n    default:\n      LWIP_ASSERT(\"unknown dns_table entry state:\", 0);\n      break;\n  }\n}\n\n/**\n * Call dns_check_entry for each entry in dns_table - check all entries.\n */\nstatic void ICACHE_FLASH_ATTR\ndns_check_entries(void)\n{\n  u8_t i;\n\n  for (i = 0; i < DNS_TABLE_SIZE; ++i) {\n    dns_check_entry(i);\n  }\n}\n\n/**\n * Receive input function for DNS response packets arriving for the dns UDP pcb.\n *\n * @params see udp.h\n */\nstatic void ICACHE_FLASH_ATTR\ndns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)\n{\n  u16_t i;\n  char *pHostname;\n  struct dns_hdr *hdr;\n  struct dns_answer ans;\n  struct dns_table_entry *pEntry;\n  u16_t nquestions, nanswers;\n\n  u8_t* dns_payload_buffer = (u8_t* )os_zalloc(LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE));\n  dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);\n\n  LWIP_UNUSED_ARG(arg);\n  LWIP_UNUSED_ARG(pcb);\n  LWIP_UNUSED_ARG(addr);\n  LWIP_UNUSED_ARG(port);\n\n  /* is the dns message too big ? */\n  if (p->tot_len > DNS_MSG_SIZE) {\n    LWIP_DEBUGF(DNS_DEBUG, (\"dns_recv: pbuf too big\\n\"));\n    /* free pbuf and return */\n    goto memerr;\n  }\n\n  /* is the dns message big enough ? */\n  if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {\n    LWIP_DEBUGF(DNS_DEBUG, (\"dns_recv: pbuf too small\\n\"));\n    /* free pbuf and return */\n    goto memerr;\n  }\n\n  /* copy dns payload inside static buffer for processing */ \n  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {\n    /* The ID in the DNS header should be our entry into the name table. */\n    hdr = (struct dns_hdr*)dns_payload;\n    i = htons(hdr->id);\n    i = i - dns_random;\n    if (i < DNS_TABLE_SIZE) {\n      pEntry = &dns_table[i];\n      if(pEntry->state == DNS_STATE_ASKING) {\n        /* This entry is now completed. */\n        pEntry->state = DNS_STATE_DONE;\n        pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;\n\n        /* We only care about the question(s) and the answers. The authrr\n           and the extrarr are simply discarded. */\n        nquestions = htons(hdr->numquestions);\n        nanswers   = htons(hdr->numanswers);\n\n        /* Check for error. If so, call callback to inform. */\n        if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {\n          LWIP_DEBUGF(DNS_DEBUG, (\"dns_recv: \\\"%s\\\": error in flags\\n\", pEntry->name));\n          /* call callback to indicate error, clean up memory and return */\n          goto responseerr;\n        }\n\n#if DNS_DOES_NAME_CHECK\n        /* Check if the name in the \"question\" part match with the name in the entry. */\n        if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {\n          LWIP_DEBUGF(DNS_DEBUG, (\"dns_recv: \\\"%s\\\": response not match to query\\n\", pEntry->name));\n          /* call callback to indicate error, clean up memory and return */\n          goto responseerr;\n        }\n#endif /* DNS_DOES_NAME_CHECK */\n\n        /* Skip the name in the \"question\" part */\n        pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;\n\n        while (nanswers > 0) {\n          /* skip answer resource record's host name */\n          pHostname = (char *) dns_parse_name((unsigned char *)pHostname);\n\n          /* Check for IP address type and Internet class. Others are discarded. */\n          SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);\n          if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&\n             (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {\n            /* read the answer resource record's TTL, and maximize it if needed */\n            pEntry->ttl = ntohl(ans.ttl);\n            if (pEntry->ttl > DNS_MAX_TTL) {\n              pEntry->ttl = DNS_MAX_TTL;\n            }\n            /* read the IP address after answer resource record's header */\n            SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));\n            LWIP_DEBUGF(DNS_DEBUG, (\"dns_recv: \\\"%s\\\": response = \", pEntry->name));\n            ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));\n            LWIP_DEBUGF(DNS_DEBUG, (\"\\n\"));\n            /* call specified callback function if provided */\n            if (pEntry->found) {\n              (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);\n            }\n            /* deallocate memory and return */\n            goto memerr;\n          } else {\n            pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);\n          }\n          --nanswers;\n        }\n        LWIP_DEBUGF(DNS_DEBUG, (\"dns_recv: \\\"%s\\\": error in response\\n\", pEntry->name));\n        /* call callback to indicate error, clean up memory and return */\n        goto responseerr;\n      }\n    }\n  }\n\n  /* deallocate memory and return */\n  goto memerr;\n\nresponseerr:\n  /* ERROR: call specified callback function with NULL as name to indicate an error */\n  if (pEntry->found) {\n    (*pEntry->found)(pEntry->name, NULL, pEntry->arg);\n  }\n  /* flush this entry */\n  pEntry->state = DNS_STATE_UNUSED;\n  pEntry->found = NULL;\n\nmemerr:\n  /* free pbuf */\n  pbuf_free(p);\n  os_free(dns_payload_buffer);\n  return;\n}\n\n/**\n * Queues a new hostname to resolve and sends out a DNS query for that hostname\n *\n * @param name the hostname that is to be queried\n * @param found a callback founction to be called on success, failure or timeout\n * @param callback_arg argument to pass to the callback function\n * @return @return a err_t return code.\n */\nstatic err_t ICACHE_FLASH_ATTR\ndns_enqueue(const char *name, dns_found_callback found, void *callback_arg)\n{\n  u8_t i;\n  u8_t lseq, lseqi;\n  struct dns_table_entry *pEntry = NULL;\n  size_t namelen;\n\n  /* search an unused entry, or the oldest one */\n  lseq = lseqi = 0;\n  for (i = 0; i < DNS_TABLE_SIZE; ++i) {\n    pEntry = &dns_table[i];\n    /* is it an unused entry ? */\n    if (pEntry->state == DNS_STATE_UNUSED)\n      break;\n\n    /* check if this is the oldest completed entry */\n    if (pEntry->state == DNS_STATE_DONE) {\n      if ((dns_seqno - pEntry->seqno) > lseq) {\n        lseq = dns_seqno - pEntry->seqno;\n        lseqi = i;\n      }\n    }\n  }\n\n  /* if we don't have found an unused entry, use the oldest completed one */\n  if (i == DNS_TABLE_SIZE) {\n    if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {\n      /* no entry can't be used now, table is full */\n      LWIP_DEBUGF(DNS_DEBUG, (\"dns_enqueue: \\\"%s\\\": DNS entries table is full\\n\", name));\n      return ERR_MEM;\n    } else {\n      /* use the oldest completed one */\n      i = lseqi;\n      pEntry = &dns_table[i];\n    }\n  }\n\n  /* use this entry */\n  LWIP_DEBUGF(DNS_DEBUG, (\"dns_enqueue: \\\"%s\\\": use DNS entry %\"U16_F\"\\n\", name, (u16_t)(i)));\n\n  /* fill the entry */\n  pEntry->state = DNS_STATE_NEW;\n  pEntry->seqno = dns_seqno++;\n  pEntry->found = found;\n  pEntry->arg   = callback_arg;\n  namelen = LWIP_MIN(os_strlen(name), DNS_MAX_NAME_LENGTH-1);\n  MEMCPY(pEntry->name, name, namelen);\n  pEntry->name[namelen] = 0;\n\n  /* force to send query without waiting timer */\n  dns_check_entry(i);\n\n  /* dns query is enqueued */\n  return ERR_INPROGRESS;\n}\n\n/**\n * Resolve a hostname (string) into an IP address.\n * NON-BLOCKING callback version for use with raw API!!!\n *\n * Returns immediately with one of err_t return codes:\n * - ERR_OK if hostname is a valid IP address string or the host\n *   name is already in the local names table.\n * - ERR_INPROGRESS enqueue a request to be sent to the DNS server\n *   for resolution if no errors are present.\n * - ERR_ARG: dns client not initialized or invalid hostname\n *\n * @param hostname the hostname that is to be queried\n * @param addr pointer to a ip_addr_t where to store the address if it is already\n *             cached in the dns_table (only valid if ERR_OK is returned!)\n * @param found a callback function to be called on success, failure or timeout (only if\n *              ERR_INPROGRESS is returned!)\n * @param callback_arg argument to pass to the callback function\n * @return a err_t return code.\n */\nerr_t ICACHE_FLASH_ATTR\ndns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,\n                  void *callback_arg)\n{\n  u32_t ipaddr;\n  /* not initialized or no valid server yet, or invalid addr pointer\n   * or invalid hostname or invalid hostname length */\n  if ((dns_pcb == NULL) || (addr == NULL) ||\n      (!hostname) || (!hostname[0]) ||\n      (os_strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {\n    return ERR_ARG;\n  }\n\n#if LWIP_HAVE_LOOPIF\n  if (strcmp(hostname, \"localhost\")==0) {\n    ip_addr_set_loopback(addr);\n    return ERR_OK;\n  }\n#endif /* LWIP_HAVE_LOOPIF */\n\n  /* host name already in octet notation? set ip addr and return ERR_OK */\n  ipaddr = ipaddr_addr(hostname);\n  if (ipaddr == IPADDR_NONE) {\n    /* already have this address cached? */\n//    ipaddr = dns_lookup(hostname);\n  }\n  if (ipaddr != IPADDR_NONE) {\n    ip4_addr_set_u32(addr, ipaddr);\n    return ERR_OK;\n  }\n\n  /* queue query with specified callback */\n  return dns_enqueue(hostname, found, callback_arg);\n}\n\n#endif /* LWIP_DNS */\n"
  },
  {
    "path": "app/lwip/core/init.c",
    "content": "/**\n * @file\n * Modules initialization\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/init.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/sockets.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/raw.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/tcp_impl.h\"\n#include \"lwip/snmp_msg.h\"\n#include \"lwip/autoip.h\"\n#include \"lwip/igmp.h\"\n#include \"lwip/dns.h\"\n#include \"lwip/timers.h\"\n#include \"netif/etharp.h\"\n\n/* Compile-time sanity checks for configuration errors.\n * These can be done independently of LWIP_DEBUG, without penalty.\n */\n#ifndef BYTE_ORDER\n  #error \"BYTE_ORDER is not defined, you have to define it in your cc.h\"\n#endif\n#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)\n  #error \"If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_ARP && ARP_QUEUEING)\n  #error \"If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_UDP && LWIP_UDPLITE)\n  #error \"If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_UDP && LWIP_SNMP)\n  #error \"If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_UDP && LWIP_DHCP)\n  #error \"If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_UDP && LWIP_IGMP)\n  #error \"If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_UDP && LWIP_SNMP)\n  #error \"If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_UDP && LWIP_DNS)\n  #error \"If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h\"\n#endif\n#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))\n  #error \"If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h\"\n#endif\n#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))\n  #error \"If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h\"\n#endif\n#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))\n  #error \"If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h\"\n#endif\n//#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))\n//  #error \"If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h\"\n//#endif\n//#if (LWIP_TCP && (TCP_WND > 0xffff))\n//  #error \"If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h\"\n//#endif\n#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))\n  #error \"If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h\"\n#endif\n#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))\n  #error \"TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work\"\n#endif\n//#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))\n//  #error \"If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h\"\n//#endif\n#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))\n  #error \"If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t\"\n#endif\n#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))\n  #error \"If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h\"\n#endif\n#if (LWIP_NETIF_API && (NO_SYS==1))\n  #error \"If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h\"\n#endif\n#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))\n  #error \"If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h\"\n#endif\n#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))\n  #error \"If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_NETCONN && LWIP_SOCKET)\n  #error \"If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h\"\n#endif\n#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)\n  #error \"If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h\"\n#endif\n#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK)\n  #error \"If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h\"\n#endif\n#if (!LWIP_ARP && LWIP_AUTOIP)\n  #error \"If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h\"\n#endif\n#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))\n  #error \"If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h\"\n#endif\n#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))\n  #error \"If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h\"\n#endif\n#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))\n  #error \"One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h\"\n#endif\n/* There must be sufficient timeouts, taking into account requirements of the subsystems. */\n#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))\n  #error \"MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts\"\n#endif\n#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))\n  #error \"MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!\"\n#endif\n#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)\n  #error \"MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h\"\n#endif\n#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)\n  #error \"MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h\"\n#endif\n#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)\n  #error \"PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf\"\n#endif\n#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)\n  #error \"TCP_QUEUE_OOSEQ requires LWIP_TCP\"\n#endif\n#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))\n  #error \"you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST\"\n#endif\n#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT\n  #error \"PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on\"\n#endif\n#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT)\n  #error \"LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT\"\n#endif\n#if LWIP_IGMP && !defined(LWIP_RAND)\n  #error \"When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value\"\n#endif\n#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING\n  #error \"When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too\"\n#endif\n#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE\n  #error \"LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets\"\n#endif\n#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF\n  #error \"LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues\"\n#endif\n\n\n/* Compile-time checks for deprecated options.\n */\n#ifdef MEMP_NUM_TCPIP_MSG\n  #error \"MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h.\"\n#endif\n#ifdef MEMP_NUM_API_MSG\n  #error \"MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h.\"\n#endif\n#ifdef TCP_REXMIT_DEBUG\n  #error \"TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h.\"\n#endif\n#ifdef RAW_STATS\n  #error \"RAW_STATS option is deprecated. Remove it from your lwipopts.h.\"\n#endif\n#ifdef ETHARP_QUEUE_FIRST\n  #error \"ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h.\"\n#endif\n#ifdef ETHARP_ALWAYS_INSERT\n  #error \"ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h.\"\n#endif\n\n#ifdef LWIP_DEBUG\nstatic void ICACHE_FLASH_ATTR\nlwip_sanity_check(void)\n{\n  /* Warnings */\n#if LWIP_NETCONN\n  if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\\n\"));\n#endif /* LWIP_NETCONN */\n#if LWIP_TCP\n  if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\\n\"));\n  if (TCP_SND_BUF < 2 * TCP_MSS)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\\n\"));\n  if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\\n\"));\n  if (TCP_SNDLOWAT >= TCP_SND_BUF)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\\n\"));\n  if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\\n\"));\n  if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\\n\"));\n  if (TCP_WND < TCP_MSS)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\\n\"));\n#endif /* LWIP_TCP */\n#if LWIP_SOCKET\n  /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */\n  if (SO_ACCEPTCONN != SOF_ACCEPTCONN)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\\n\"));\n  if (SO_REUSEADDR != SOF_REUSEADDR)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\\n\"));\n  if (SO_KEEPALIVE != SOF_KEEPALIVE)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\\n\"));\n  if (SO_BROADCAST != SOF_BROADCAST)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\\n\"));\n  if (SO_LINGER != SOF_LINGER)\n    LWIP_PLATFORM_DIAG((\"lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\\n\"));\n#endif /* LWIP_SOCKET */\n}\n#else  /* LWIP_DEBUG */\n#define lwip_sanity_check()\n#endif /* LWIP_DEBUG */\n\n/**\n * Perform Sanity check of user-configurable values, and initialize all modules.\n */\nvoid\nlwip_init(void)\n{\n  MEMP_NUM_TCP_PCB = 5;\n  TCP_WND = (4 * TCP_MSS);\n  TCP_MAXRTX = 12;\n  TCP_SYNMAXRTX = 6;\n\n  /* Sanity check user-configurable values */\n  lwip_sanity_check();\n\n  /* Modules initialization */\n  stats_init();\n#if !NO_SYS\n  sys_init();\n#endif /* !NO_SYS */\n#if 0\n  mem_init(&_bss_end);\n#endif\n  memp_init();\n\n  pbuf_init();\n\n  netif_init();\n \n#if LWIP_SOCKET\n  lwip_socket_init();\n#endif /* LWIP_SOCKET */\n  ip_init();\n \n#if LWIP_ARP\n  etharp_init();\n\n#endif /* LWIP_ARP */\n#if LWIP_RAW\n  raw_init();\n \n#endif /* LWIP_RAW */\n#if LWIP_UDP\n  udp_init();\n \n#endif /* LWIP_UDP */\n#if LWIP_TCP\n  tcp_init();\n  \n#endif /* LWIP_TCP */\n#if LWIP_SNMP\n  snmp_init();\n  \n#endif /* LWIP_SNMP */\n#if LWIP_AUTOIP\n  autoip_init();\n \n#endif /* LWIP_AUTOIP */\n#if LWIP_IGMP\n  igmp_init();\n\n#endif /* LWIP_IGMP */\n#if LWIP_DNS\n  dns_init();\n\n#endif /* LWIP_DNS */\n\n#if LWIP_TIMERS\n  sys_timeouts_init();\n#endif /* LWIP_TIMERS */\n}\n"
  },
  {
    "path": "app/lwip/core/ipv4/Makefile",
    "content": "\r\n#############################################################\r\n# Required variables for each makefile\r\n# Discard this section from all parent makefiles\r\n# Expected variables (with automatic defaults):\r\n#   CSRCS (all \"C\" files in the dir)\r\n#   SUBDIRS (all subdirs with a Makefile)\r\n#   GEN_LIBS - list of libs to be generated ()\r\n#   GEN_IMAGES - list of images to be generated ()\r\n#   COMPONENTS_xxx - a list of libs/objs in the form\r\n#     subdir/lib to be extracted and rolled up into\r\n#     a generated lib/image xxx.a ()\r\n#\r\nifndef PDIR\r\n\r\nGEN_LIBS = liblwipipv4.a\r\n\r\nendif\r\n\r\n\r\n#############################################################\r\n# Configuration i.e. compile options etc.\r\n# Target specific stuff (defines etc.) goes in here!\r\n# Generally values applying to a tree are captured in the\r\n#   makefile at its root level - these are then overridden\r\n#   for a subtree within the makefile rooted therein\r\n#\r\n#DEFINES += \r\n\r\n#############################################################\r\n# Recursion Magic - Don't touch this!!\r\n#\r\n# Each subtree potentially has an include directory\r\n#   corresponding to the common APIs applicable to modules\r\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\r\n#   of a module can only contain the include directories up\r\n#   its parent path, and not its siblings\r\n#\r\n# Required for each makefile to inherit from the parent\r\n#\r\n\r\nINCLUDES := $(INCLUDES) -I $(PDIR)include\r\nINCLUDES += -I ./\r\nPDIR := ../$(PDIR)\r\nsinclude $(PDIR)Makefile\r\n\r\n"
  },
  {
    "path": "app/lwip/core/ipv4/autoip.c",
    "content": "/**\n * @file\n * AutoIP Automatic LinkLocal IP Configuration\n *\n */\n\n/*\n *\n * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * Author: Dominik Spies <kontakt@dspies.de>\n *\n * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform\n * with RFC 3927.\n *\n *\n * Please coordinate changes and requests with Dominik Spies\n * <kontakt@dspies.de>\n */\n\n/*******************************************************************************\n * USAGE:\n * \n * define LWIP_AUTOIP 1  in your lwipopts.h\n * \n * If you don't use tcpip.c (so, don't call, you don't call tcpip_init):\n * - First, call autoip_init().\n * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,\n *   that should be defined in autoip.h.\n *   I recommend a value of 100. The value must divide 1000 with a remainder almost 0.\n *   Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....\n *\n * Without DHCP:\n * - Call autoip_start() after netif_add().\n * \n * With DHCP:\n * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.\n * - Configure your DHCP Client.\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/mem.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/autoip.h\"\n#include \"netif/etharp.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\n/* 169.254.0.0 */\n#define AUTOIP_NET         0xA9FE0000\n/* 169.254.1.0 */\n#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)\n/* 169.254.254.255 */\n#define AUTOIP_RANGE_END   (AUTOIP_NET | 0xFEFF)\n\n\n/** Pseudo random macro based on netif informations.\n * You could use \"rand()\" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */\n#ifndef LWIP_AUTOIP_RAND\n#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \\\n                                   ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \\\n                                   ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \\\n                                   ((u32_t)((netif->hwaddr[4]) & 0xff))) + \\\n                                   (netif->autoip?netif->autoip->tried_llipaddr:0))\n#endif /* LWIP_AUTOIP_RAND */\n\n/**\n * Macro that generates the initial IP address to be tried by AUTOIP.\n * If you want to override this, define it to something else in lwipopts.h.\n */\n#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR\n#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \\\n  htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \\\n                 ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))\n#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */\n\n/* static functions */\nstatic void autoip_handle_arp_conflict(struct netif *netif);\n\n/* creates a pseudo random LL IP-Address for a network interface */\nstatic void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr);\n\n/* sends an ARP probe */\nstatic err_t autoip_arp_probe(struct netif *netif);\n\n/* sends an ARP announce */\nstatic err_t autoip_arp_announce(struct netif *netif);\n\n/* configure interface for use with current LL IP-Address */\nstatic err_t autoip_bind(struct netif *netif);\n\n/* start sending probes for llipaddr */\nstatic void autoip_start_probing(struct netif *netif);\n\n/**\n * Initialize this module\n */\nvoid\nautoip_init(void)\n{\n  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, (\"autoip_init()\\n\"));\n}\n\n/** Set a statically allocated struct autoip to work with.\n * Using this prevents autoip_start to allocate it using mem_malloc.\n *\n * @param netif the netif for which to set the struct autoip\n * @param dhcp (uninitialised) dhcp struct allocated by the application\n */\nvoid\nautoip_set_struct(struct netif *netif, struct autoip *autoip)\n{\n  LWIP_ASSERT(\"netif != NULL\", netif != NULL);\n  LWIP_ASSERT(\"autoip != NULL\", autoip != NULL);\n  LWIP_ASSERT(\"netif already has a struct autoip set\", netif->autoip == NULL);\n\n  /* clear data structure */\n  os_memset(autoip, 0, sizeof(struct autoip));\n  /* autoip->state = AUTOIP_STATE_OFF; */\n  netif->autoip = autoip;\n}\n\n/** Restart AutoIP client and check the next address (conflict detected)\n *\n * @param netif The netif under AutoIP control\n */\nstatic void\nautoip_restart(struct netif *netif)\n{\n  netif->autoip->tried_llipaddr++;\n  autoip_start(netif);\n}\n\n/**\n * Handle a IP address conflict after an ARP conflict detection\n */\nstatic void\nautoip_handle_arp_conflict(struct netif *netif)\n{\n  /* Somehow detect if we are defending or retreating */\n  unsigned char defend = 1; /* tbd */\n\n  if(defend) {\n    if(netif->autoip->lastconflict > 0) {\n      /* retreat, there was a conflicting ARP in the last\n       * DEFEND_INTERVAL seconds\n       */\n      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n        (\"autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\\n\"));\n\n      /* TODO: close all TCP sessions */\n      autoip_restart(netif);\n    } else {\n      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n        (\"autoip_handle_arp_conflict(): we are defend, send ARP Announce\\n\"));\n      autoip_arp_announce(netif);\n      netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;\n    }\n  } else {\n    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n      (\"autoip_handle_arp_conflict(): we do not defend, retreating\\n\"));\n    /* TODO: close all TCP sessions */\n    autoip_restart(netif);\n  }\n}\n\n/**\n * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255\n *\n * @param netif network interface on which create the IP-Address\n * @param ipaddr ip address to initialize\n */\nstatic void\nautoip_create_addr(struct netif *netif, ip_addr_t *ipaddr)\n{\n  /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255\n   * compliant to RFC 3927 Section 2.1\n   * We have 254 * 256 possibilities */\n\n  u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));\n  addr += netif->autoip->tried_llipaddr;\n  addr = AUTOIP_NET | (addr & 0xffff);\n  /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ \n\n  if (addr < AUTOIP_RANGE_START) {\n    addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;\n  }\n  if (addr > AUTOIP_RANGE_END) {\n    addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;\n  }\n  LWIP_ASSERT(\"AUTOIP address not in range\", (addr >= AUTOIP_RANGE_START) &&\n    (addr <= AUTOIP_RANGE_END));\n  ip4_addr_set_u32(ipaddr, htonl(addr));\n  \n  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n    (\"autoip_create_addr(): tried_llipaddr=%\"U16_F\", %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n    (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr),\n    ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));\n}\n\n/**\n * Sends an ARP probe from a network interface\n *\n * @param netif network interface used to send the probe\n */\nstatic err_t\nautoip_arp_probe(struct netif *netif)\n{\n  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,\n    (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,\n    &netif->autoip->llipaddr, ARP_REQUEST);\n}\n\n/**\n * Sends an ARP announce from a network interface\n *\n * @param netif network interface used to send the announce\n */\nstatic err_t\nautoip_arp_announce(struct netif *netif)\n{\n  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,\n    (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,\n    &netif->autoip->llipaddr, ARP_REQUEST);\n}\n\n/**\n * Configure interface for use with current LL IP-Address\n *\n * @param netif network interface to configure with current LL IP-Address\n */\nstatic err_t\nautoip_bind(struct netif *netif)\n{\n  struct autoip *autoip = netif->autoip;\n  ip_addr_t sn_mask, gw_addr;\n\n  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\n    (\"autoip_bind(netif=%p) %c%c%\"U16_F\" %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num,\n    ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr),\n    ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr)));\n\n  IP4_ADDR(&sn_mask, 255, 255, 0, 0);\n  IP4_ADDR(&gw_addr, 0, 0, 0, 0);\n\n  netif_set_ipaddr(netif, &autoip->llipaddr);\n  netif_set_netmask(netif, &sn_mask);\n  netif_set_gw(netif, &gw_addr);  \n\n  /* bring the interface up */\n  netif_set_up(netif);\n\n  return ERR_OK;\n}\n\n/**\n * Start AutoIP client\n *\n * @param netif network interface on which start the AutoIP client\n */\nerr_t\nautoip_start(struct netif *netif)\n{\n  struct autoip *autoip = netif->autoip;\n  err_t result = ERR_OK;\n\n  if(netif_is_up(netif)) {\n    netif_set_down(netif);\n  }\n\n  /* Set IP-Address, Netmask and Gateway to 0 to make sure that\n   * ARP Packets are formed correctly\n   */\n  ip_addr_set_zero(&netif->ip_addr);\n  ip_addr_set_zero(&netif->netmask);\n  ip_addr_set_zero(&netif->gw);\n\n  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n    (\"autoip_start(netif=%p) %c%c%\"U16_F\"\\n\", (void*)netif, netif->name[0],\n    netif->name[1], (u16_t)netif->num));\n  if(autoip == NULL) {\n    /* no AutoIP client attached yet? */\n    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\n      (\"autoip_start(): starting new AUTOIP client\\n\"));\n    autoip = (struct autoip *)mem_malloc(sizeof(struct autoip));\n    if(autoip == NULL) {\n      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\n        (\"autoip_start(): could not allocate autoip\\n\"));\n      return ERR_MEM;\n    }\n    os_memset(autoip, 0, sizeof(struct autoip));\n    /* store this AutoIP client in the netif */\n    netif->autoip = autoip;\n    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, (\"autoip_start(): allocated autoip\"));\n  } else {\n    autoip->state = AUTOIP_STATE_OFF;\n    autoip->ttw = 0;\n    autoip->sent_num = 0;\n    ip_addr_set_zero(&autoip->llipaddr);\n    autoip->lastconflict = 0;\n  }\n\n  autoip_create_addr(netif, &(autoip->llipaddr));\n  autoip_start_probing(netif);\n\n  return result;\n}\n\nstatic void\nautoip_start_probing(struct netif *netif)\n{\n  struct autoip *autoip = netif->autoip;\n\n  autoip->state = AUTOIP_STATE_PROBING;\n  autoip->sent_num = 0;\n  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n     (\"autoip_start_probing(): changing state to PROBING: %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n      ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),\n      ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));\n\n  /* time to wait to first probe, this is randomly\n   * choosen out of 0 to PROBE_WAIT seconds.\n   * compliant to RFC 3927 Section 2.2.1\n   */\n  autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));\n\n  /*\n   * if we tried more then MAX_CONFLICTS we must limit our rate for\n   * accquiring and probing address\n   * compliant to RFC 3927 Section 2.2.1\n   */\n  if(autoip->tried_llipaddr > MAX_CONFLICTS) {\n    autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;\n  }\n}\n\n/**\n * Handle a possible change in the network configuration.\n *\n * If there is an AutoIP address configured, take the interface down\n * and begin probing with the same address.\n */\nvoid\nautoip_network_changed(struct netif *netif)\n{\n  if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {\n    netif_set_down(netif);\n    autoip_start_probing(netif);\n  }\n}\n\n/**\n * Stop AutoIP client\n *\n * @param netif network interface on which stop the AutoIP client\n */\nerr_t\nautoip_stop(struct netif *netif)\n{\n  netif->autoip->state = AUTOIP_STATE_OFF;\n  netif_set_down(netif);\n  return ERR_OK;\n}\n\n/**\n * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds\n */\nvoid\nautoip_tmr()\n{\n  struct netif *netif = netif_list;\n  /* loop through netif's */\n  while (netif != NULL) {\n    /* only act on AutoIP configured interfaces */\n    if (netif->autoip != NULL) {\n      if(netif->autoip->lastconflict > 0) {\n        netif->autoip->lastconflict--;\n      }\n\n      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\n        (\"autoip_tmr() AutoIP-State: %\"U16_F\", ttw=%\"U16_F\"\\n\",\n        (u16_t)(netif->autoip->state), netif->autoip->ttw));\n\n      switch(netif->autoip->state) {\n        case AUTOIP_STATE_PROBING:\n          if(netif->autoip->ttw > 0) {\n            netif->autoip->ttw--;\n          } else {\n            if(netif->autoip->sent_num >= PROBE_NUM) {\n              netif->autoip->state = AUTOIP_STATE_ANNOUNCING;\n              netif->autoip->sent_num = 0;\n              netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;\n              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n                 (\"autoip_tmr(): changing state to ANNOUNCING: %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n                  ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),\n                  ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));\n            } else {\n              autoip_arp_probe(netif);\n              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\n                (\"autoip_tmr() PROBING Sent Probe\\n\"));\n              netif->autoip->sent_num++;\n              /* calculate time to wait to next probe */\n              netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %\n                ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +\n                PROBE_MIN * AUTOIP_TICKS_PER_SECOND);\n            }\n          }\n          break;\n\n        case AUTOIP_STATE_ANNOUNCING:\n          if(netif->autoip->ttw > 0) {\n            netif->autoip->ttw--;\n          } else {\n            if(netif->autoip->sent_num == 0) {\n             /* We are here the first time, so we waited ANNOUNCE_WAIT seconds\n              * Now we can bind to an IP address and use it.\n              *\n              * autoip_bind calls netif_set_up. This triggers a gratuitous ARP\n              * which counts as an announcement.\n              */\n              autoip_bind(netif);\n            } else {\n              autoip_arp_announce(netif);\n              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\n                (\"autoip_tmr() ANNOUNCING Sent Announce\\n\"));\n            }\n            netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;\n            netif->autoip->sent_num++;\n\n            if(netif->autoip->sent_num >= ANNOUNCE_NUM) {\n                netif->autoip->state = AUTOIP_STATE_BOUND;\n                netif->autoip->sent_num = 0;\n                netif->autoip->ttw = 0;\n                 LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n                    (\"autoip_tmr(): changing state to BOUND: %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n                     ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr),\n                     ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr)));\n            }\n          }\n          break;\n      }\n    }\n    /* proceed to next network interface */\n    netif = netif->next;\n  }\n}\n\n/**\n * Handles every incoming ARP Packet, called by etharp_arp_input.\n *\n * @param netif network interface to use for autoip processing\n * @param hdr Incoming ARP packet\n */\nvoid\nautoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)\n{\n  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, (\"autoip_arp_reply()\\n\"));\n  if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {\n   /* when ip.src == llipaddr && hw.src != netif->hwaddr\n    *\n    * when probing  ip.dst == llipaddr && hw.src != netif->hwaddr\n    * we have a conflict and must solve it\n    */\n    ip_addr_t sipaddr, dipaddr;\n    struct eth_addr netifaddr;\n    ETHADDR16_COPY(netifaddr.addr, netif->hwaddr);\n\n    /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without\n     * structure packing (not using structure copy which breaks strict-aliasing rules).\n     */\n    IPADDR2_COPY(&sipaddr, &hdr->sipaddr);\n    IPADDR2_COPY(&dipaddr, &hdr->dipaddr);\n      \n    if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||\n        ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&\n         (netif->autoip->sent_num == 0))) {\n     /* RFC 3927 Section 2.2.1:\n      * from beginning to after ANNOUNCE_WAIT\n      * seconds we have a conflict if\n      * ip.src == llipaddr OR\n      * ip.dst == llipaddr && hw.src != own hwaddr\n      */\n      if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||\n          (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&\n           !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {\n        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,\n          (\"autoip_arp_reply(): Probe Conflict detected\\n\"));\n        autoip_restart(netif);\n      }\n    } else {\n     /* RFC 3927 Section 2.5:\n      * in any state we have a conflict if\n      * ip.src == llipaddr && hw.src != own hwaddr\n      */\n      if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&\n          !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {\n        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,\n          (\"autoip_arp_reply(): Conflicting ARP-Packet detected\\n\"));\n        autoip_handle_arp_conflict(netif);\n      }\n    }\n  }\n}\n\n#endif /* LWIP_AUTOIP */\n"
  },
  {
    "path": "app/lwip/core/ipv4/icmp.c",
    "content": "/**\n * @file\n * ICMP - Internet Control Message Protocol\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n/* Some ICMP messages should be passed to the transport protocols. This\n   is not implemented. */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/icmp.h\"\n#include \"lwip/inet_chksum.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/def.h\"\n#include \"lwipopts.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/snmp.h\"\n\n#include <string.h>\n\n/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be\n * used to modify and send a response packet (and to 1 if this is not the case,\n * e.g. when link header is stripped of when receiving) */\n#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN\n#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1\n#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */\n\n/* The amount of data from the original packet to return in a dest-unreachable */\n#define ICMP_DEST_UNREACH_DATASIZE 8\n\nstatic void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);\n\n/**\n * Processes ICMP input packets, called from ip_input().\n *\n * Currently only processes icmp echo requests and sends\n * out the echo response.\n *\n * @param p the icmp echo request packet, p->payload pointing to the ip header\n * @param inp the netif on which this packet was received\n */\nvoid\nicmp_input(struct pbuf *p, struct netif *inp)\n{\n  u8_t type;\n#ifdef LWIP_DEBUG\n  u8_t code;\n#endif /* LWIP_DEBUG */\n  struct icmp_echo_hdr *iecho;\n  struct ip_hdr *iphdr;\n  s16_t hlen;\n\n  ICMP_STATS_INC(icmp.recv);\n  snmp_inc_icmpinmsgs();\n\n\n  iphdr = (struct ip_hdr *)p->payload;\n  hlen = IPH_HL(iphdr) * 4;\n  if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {\n    LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_input: short ICMP (%\"U16_F\" bytes) received\\n\", p->tot_len));\n    goto lenerr;\n  }\n\n  type = *((u8_t *)p->payload);\n#ifdef LWIP_DEBUG\n  code = *(((u8_t *)p->payload)+1);\n#endif /* LWIP_DEBUG */\n  switch (type) {\n  case ICMP_ER:\n    /* This is OK, echo reply might have been parsed by a raw PCB\n       (as obviously, an echo request has been sent, too). */\n    break; \n  case ICMP_ECHO:\n#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING\n    {\n      int accepted = 1;\n#if !LWIP_MULTICAST_PING\n      /* multicast destination address? */\n      if (ip_addr_ismulticast(&current_iphdr_dest)) {\n        accepted = 0;\n      }\n#endif /* LWIP_MULTICAST_PING */\n#if !LWIP_BROADCAST_PING\n      /* broadcast destination address? */\n      if (ip_addr_isbroadcast(&current_iphdr_dest, inp)) {\n        accepted = 0;\n      }\n#endif /* LWIP_BROADCAST_PING */\n      /* broadcast or multicast destination address not acceptd? */\n      if (!accepted) {\n        LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_input: Not echoing to multicast or broadcast pings\\n\"));\n        ICMP_STATS_INC(icmp.err);\n        pbuf_free(p);\n        return;\n      }\n    }\n#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */\n    LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_input: ping\\n\"));\n    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {\n      LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_input: bad ICMP echo received\\n\"));\n      goto lenerr;\n    }\n    if (inet_chksum_pbuf(p) != 0) {\n      LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_input: checksum failed for received ICMP echo\\n\"));\n      pbuf_free(p);\n      ICMP_STATS_INC(icmp.chkerr);\n      snmp_inc_icmpinerrors();\n      return;\n    }\n#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN\n    if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {\n      /* p is not big enough to contain link headers\n       * allocate a new one and copy p into it\n       */\n      struct pbuf *r;\n      /* switch p->payload to ip header */\n      if (pbuf_header(p, hlen)) {\n        LWIP_ASSERT(\"icmp_input: moving p->payload to ip header failed\\n\", 0);\n        goto memerr;\n      }\n      /* allocate new packet buffer with space for link headers */\n      r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);\n      if (r == NULL) {\n        LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_input: allocating new pbuf failed\\n\"));\n        goto memerr;\n      }\n      LWIP_ASSERT(\"check that first pbuf can hold struct the ICMP header\",\n                  (r->len >= hlen + sizeof(struct icmp_echo_hdr)));\n      /* copy the whole packet including ip header */\n      if (pbuf_copy(r, p) != ERR_OK) {\n        LWIP_ASSERT(\"icmp_input: copying to new pbuf failed\\n\", 0);\n        goto memerr;\n      }\n      iphdr = (struct ip_hdr *)r->payload;\n      /* switch r->payload back to icmp header */\n      if (pbuf_header(r, -hlen)) {\n        LWIP_ASSERT(\"icmp_input: restoring original p->payload failed\\n\", 0);\n        goto memerr;\n      }\n      /* free the original p */\n      pbuf_free(p);\n      /* we now have an identical copy of p that has room for link headers */\n      p = r;\n    } else {\n      /* restore p->payload to point to icmp header */\n      if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {\n        LWIP_ASSERT(\"icmp_input: restoring original p->payload failed\\n\", 0);\n        goto memerr;\n      }\n    }\n#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */\n    /* At this point, all checks are OK. */\n    /* We generate an answer by switching the dest and src ip addresses,\n     * setting the icmp type to ECHO_RESPONSE and updating the checksum. */\n    iecho = (struct icmp_echo_hdr *)p->payload;\n    ip_addr_copy(iphdr->src, *ip_current_dest_addr());\n    ip_addr_copy(iphdr->dest, *ip_current_src_addr());\n    ICMPH_TYPE_SET(iecho, ICMP_ER);\n    /* adjust the checksum */\n    if (iecho->chksum >= PP_HTONS(0xffff - (ICMP_ECHO << 8))) {\n      iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;\n    } else {\n      iecho->chksum += PP_HTONS(ICMP_ECHO << 8);\n    }\n\n    /* Set the correct TTL and recalculate the header checksum. */\n    IPH_TTL_SET(iphdr, ICMP_TTL);\n    IPH_CHKSUM_SET(iphdr, 0);\n#if CHECKSUM_GEN_IP\n    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\n#endif /* CHECKSUM_GEN_IP */\n\n    ICMP_STATS_INC(icmp.xmit);\n    /* increase number of messages attempted to send */\n    snmp_inc_icmpoutmsgs();\n    /* increase number of echo replies attempted to send */\n    snmp_inc_icmpoutechoreps();\n\n    if(pbuf_header(p, hlen)) {\n      LWIP_ASSERT(\"Can't move over header in packet\", 0);\n    } else {\n      err_t ret;\n      /* send an ICMP packet, src addr is the dest addr of the curren packet */\n      ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL,\n                   ICMP_TTL, 0, IP_PROTO_ICMP, inp);\n      if (ret != ERR_OK) {\n        LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_input: ip_output_if returned an error: %c.\\n\", ret));\n      }\n    }\n    break;\n  default:\n    LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_input: ICMP type %\"S16_F\" code %\"S16_F\" not supported.\\n\", \n                (s16_t)type, (s16_t)code));\n    ICMP_STATS_INC(icmp.proterr);\n    ICMP_STATS_INC(icmp.drop);\n  }\n  pbuf_free(p);\n  return;\nlenerr:\n  pbuf_free(p);\n  ICMP_STATS_INC(icmp.lenerr);\n  snmp_inc_icmpinerrors();\n  return;\n#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN\nmemerr:\n  pbuf_free(p);\n  ICMP_STATS_INC(icmp.err);\n  snmp_inc_icmpinerrors();\n  return;\n#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */\n}\n\n/**\n * Send an icmp 'destination unreachable' packet, called from ip_input() if\n * the transport layer protocol is unknown and from udp_input() if the local\n * port is not bound.\n *\n * @param p the input packet for which the 'unreachable' should be sent,\n *          p->payload pointing to the IP header\n * @param t type of the 'unreachable' packet\n */\nvoid\nicmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)\n{\n  icmp_send_response(p, ICMP_DUR, t);\n}\n\n#if IP_FORWARD || IP_REASSEMBLY\n/**\n * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.\n *\n * @param p the input packet for which the 'time exceeded' should be sent,\n *          p->payload pointing to the IP header\n * @param t type of the 'time exceeded' packet\n */\nvoid\nicmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)\n{\n  icmp_send_response(p, ICMP_TE, t);\n}\n\n#endif /* IP_FORWARD || IP_REASSEMBLY */\n\n/**\n * Send an icmp packet in response to an incoming packet.\n *\n * @param p the input packet for which the 'unreachable' should be sent,\n *          p->payload pointing to the IP header\n * @param type Type of the ICMP header\n * @param code Code of the ICMP header\n */\nstatic void ICACHE_FLASH_ATTR\nicmp_send_response(struct pbuf *p, u8_t type, u8_t code)\n{\n  struct pbuf *q;\n  struct ip_hdr *iphdr;\n  /* we can use the echo header here */\n  struct icmp_echo_hdr *icmphdr;\n  ip_addr_t iphdr_src;\n\n  /* ICMP header + IP header + 8 bytes of data */\n  //Ϊpbufռ䣬pbufԤIPײ̫ײռ䣬pbuf\n  //=ײ+ݳ(IPײ+8)\n  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,\n                 PBUF_RAM);\n  if (q == NULL) {//ʧܣ\n    LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\\n\"));\n    return;\n  }\n  LWIP_ASSERT(\"check that first pbuf can hold icmp message\",\n             (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));\n\n  iphdr = (struct ip_hdr *)p->payload;//ָIPݰײ\n  LWIP_DEBUGF(ICMP_DEBUG, (\"icmp_time_exceeded from \"));\n  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));\n  LWIP_DEBUGF(ICMP_DEBUG, (\" to \"));\n  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));\n  LWIP_DEBUGF(ICMP_DEBUG, (\"\\n\"));\n\n  icmphdr = (struct icmp_echo_hdr *)q->payload;//ָײ\n  icmphdr->type = type;//дֶ\n  icmphdr->code = code;//дֶ\n  icmphdr->id = 0;//ĿĲɴݱʱ\n  icmphdr->seqno = 0;//ģײʣ4ֽڶΪ0\n\n  /* copy fields from original packet IPݱIPײ+8ֽݿ*/\n  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,\n          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);\n\n  /* calculate checksum */\n  icmphdr->chksum = 0;//Уֶ0\n  icmphdr->chksum = inet_chksum(icmphdr, q->len);//дУ\n  ICMP_STATS_INC(icmp.xmit);\n  /* increase number of messages attempted to send */\n  snmp_inc_icmpoutmsgs();\n  /* increase number of destination unreachable messages attempted to send */\n  snmp_inc_icmpouttimeexcds();\n  ip_addr_copy(iphdr_src, iphdr->src);\n  ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);//IP㺯ICMP\n  pbuf_free(q);\n}\n\n#endif /* LWIP_ICMP */\n"
  },
  {
    "path": "app/lwip/core/ipv4/igmp.c",
    "content": "/**\n * @file\n * IGMP - Internet Group Management Protocol\n *\n */\n\n/*\n * Copyright (c) 2002 CITEL Technologies Ltd.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions \n * are met: \n * 1. Redistributions of source code must retain the above copyright \n *    notice, this list of conditions and the following disclaimer. \n * 2. Redistributions in binary form must reproduce the above copyright \n *    notice, this list of conditions and the following disclaimer in the \n *    documentation and/or other materials provided with the distribution. \n * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors \n *    may be used to endorse or promote products derived from this software \n *    without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \n * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE \n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \n * SUCH DAMAGE. \n *\n * This file is a contribution to the lwIP TCP/IP stack.\n * The Swedish Institute of Computer Science and Adam Dunkels\n * are specifically granted permission to redistribute this\n * source code.\n*/\n\n/*-------------------------------------------------------------\nNote 1)\nAlthough the rfc requires V1 AND V2 capability\nwe will only support v2 since now V1 is very old (August 1989)\nV1 can be added if required\n\na debug print and statistic have been implemented to\nshow this up.\n-------------------------------------------------------------\n-------------------------------------------------------------\nNote 2)\nA query for a specific group address (as opposed to ALLHOSTS)\nhas now been implemented as I am unsure if it is required\n\na debug print and statistic have been implemented to\nshow this up.\n-------------------------------------------------------------\n-------------------------------------------------------------\nNote 3)\nThe router alert rfc 2113 is implemented in outgoing packets\nbut not checked rigorously incoming\n-------------------------------------------------------------\nSteve Reynolds\n------------------------------------------------------------*/\n\n/*-----------------------------------------------------------------------------\n * RFC 988  - Host extensions for IP multicasting                         - V0\n * RFC 1054 - Host extensions for IP multicasting                         -\n * RFC 1112 - Host extensions for IP multicasting                         - V1\n * RFC 2236 - Internet Group Management Protocol, Version 2               - V2  <- this code is based on this RFC (it's the \"de facto\" standard)\n * RFC 3376 - Internet Group Management Protocol, Version 3               - V3\n * RFC 4604 - Using Internet Group Management Protocol Version 3...       - V3+\n * RFC 2113 - IP Router Alert Option                                      - \n *----------------------------------------------------------------------------*/\n\n/*-----------------------------------------------------------------------------\n * Includes\n *----------------------------------------------------------------------------*/\n\n#include \"lwip/opt.h\"\n\n#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/igmp.h\"\n#include \"lwip/debug.h\"\n#include \"lwip/def.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/inet_chksum.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/icmp.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/tcp.h\"\n#include \"lwip/stats.h\"\n\n#include \"string.h\"\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/* \n * IGMP constants\n */\n#define IGMP_TTL                       1\n#define IGMP_MINLEN                    8\n#define ROUTER_ALERT                   0x9404\n#define ROUTER_ALERTLEN                4\n\n/*\n * IGMP message types, including version number.\n */\n#define IGMP_MEMB_QUERY                0x11 /* Membership query         */\n#define IGMP_V1_MEMB_REPORT            0x12 /* Ver. 1 membership report */\n#define IGMP_V2_MEMB_REPORT            0x16 /* Ver. 2 membership report */\n#define IGMP_LEAVE_GROUP               0x17 /* Leave-group message      */\n\n/* Group  membership states */\n#define IGMP_GROUP_NON_MEMBER          0\n#define IGMP_GROUP_DELAYING_MEMBER     1\n#define IGMP_GROUP_IDLE_MEMBER         2\n\n/**\n * IGMP packet format.\n */\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct igmp_msg {\n PACK_STRUCT_FIELD(u8_t           igmp_msgtype);\n PACK_STRUCT_FIELD(u8_t           igmp_maxresp);\n PACK_STRUCT_FIELD(u16_t          igmp_checksum);\n PACK_STRUCT_FIELD(ip_addr_p_t    igmp_group_address);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n\nstatic struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr)ICACHE_FLASH_ATTR;\nstatic err_t  igmp_remove_group(struct igmp_group *group)ICACHE_FLASH_ATTR;\nstatic void   igmp_timeout( struct igmp_group *group)ICACHE_FLASH_ATTR;\nstatic void   igmp_start_timer(struct igmp_group *group, u8_t max_time)ICACHE_FLASH_ATTR;\nstatic void   igmp_stop_timer(struct igmp_group *group)ICACHE_FLASH_ATTR;\nstatic void   igmp_delaying_member(struct igmp_group *group, u8_t maxresp)ICACHE_FLASH_ATTR;\nstatic err_t  igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)ICACHE_FLASH_ATTR;\nstatic void   igmp_send(struct igmp_group *group, u8_t type)ICACHE_FLASH_ATTR;\n\n\nstatic struct igmp_group* igmp_group_list;\nstatic ip_addr_t     allsystems;\nstatic ip_addr_t     allrouters;\n\n\n/**\n * Initialize the IGMP module\n */\nvoid\nigmp_init(void)\n{\n  LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_init: initializing\\n\"));\n\n  IP4_ADDR(&allsystems, 224, 0, 0, 1);\n  IP4_ADDR(&allrouters, 224, 0, 0, 2);\n}\n\n#ifdef LWIP_DEBUG\n/**\n * Dump global IGMP groups list\n */\nvoid\nigmp_dump_group_list()\n{ \n  struct igmp_group *group = igmp_group_list;\n\n  while (group != NULL) {\n    LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_dump_group_list: [%\"U32_F\"] \", (u32_t)(group->group_state)));\n    ip_addr_debug_print(IGMP_DEBUG, &group->group_address);\n    LWIP_DEBUGF(IGMP_DEBUG, (\" on if %p\\n\", group->netif));\n    group = group->next;\n  }\n  LWIP_DEBUGF(IGMP_DEBUG, (\"\\n\"));\n}\n#else\n#define igmp_dump_group_list()\n#endif /* LWIP_DEBUG */\n\n/**\n * Start IGMP processing on interface\n *\n * @param netif network interface on which start IGMP processing\n */\nerr_t\nigmp_start(struct netif *netif)\n{\n  struct igmp_group* group;\n\n  LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_start: starting IGMP processing on if %p\\n\", netif));\n\n  group = igmp_lookup_group(netif, &allsystems);\n\n  if (group != NULL) {\n    group->group_state = IGMP_GROUP_IDLE_MEMBER;\n    group->use++;\n\n    /* Allow the igmp messages at the MAC level */\n    if (netif->igmp_mac_filter != NULL) {\n      LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_start: igmp_mac_filter(ADD \"));\n      ip_addr_debug_print(IGMP_DEBUG, &allsystems);\n      LWIP_DEBUGF(IGMP_DEBUG, (\") on if %p\\n\", netif));\n      netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);\n    }\n\n    return ERR_OK;\n  }\n\n  return ERR_MEM;\n}\n\n/**\n * Stop IGMP processing on interface\n *\n * @param netif network interface on which stop IGMP processing\n */\nerr_t\nigmp_stop(struct netif *netif)\n{\n  struct igmp_group *group = igmp_group_list;\n  struct igmp_group *prev  = NULL;\n  struct igmp_group *next;\n\n  /* look for groups joined on this interface further down the list */\n  while (group != NULL) {\n    next = group->next;\n    /* is it a group joined on this interface? */\n    if (group->netif == netif) {\n      /* is it the first group of the list? */\n      if (group == igmp_group_list) {\n        igmp_group_list = next;\n      }\n      /* is there a \"previous\" group defined? */\n      if (prev != NULL) {\n        prev->next = next;\n      }\n      /* disable the group at the MAC level */\n      if (netif->igmp_mac_filter != NULL) {\n        LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_stop: igmp_mac_filter(DEL \"));\n        ip_addr_debug_print(IGMP_DEBUG, &group->group_address);\n        LWIP_DEBUGF(IGMP_DEBUG, (\") on if %p\\n\", netif));\n        netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);\n      }\n      /* free group */\n      memp_free(MEMP_IGMP_GROUP, group);\n    } else {\n      /* change the \"previous\" */\n      prev = group;\n    }\n    /* move to \"next\" */\n    group = next;\n  }\n  return ERR_OK;\n}\n\n/**\n * Report IGMP memberships for this interface\n *\n * @param netif network interface on which report IGMP memberships\n */\nvoid\nigmp_report_groups(struct netif *netif)\n{\n  struct igmp_group *group = igmp_group_list;\n\n  LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_report_groups: sending IGMP reports on if %p\\n\", netif));\n\n  while (group != NULL) {\n    if (group->netif == netif) {\n      igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR);\n    }\n    group = group->next;\n  }\n}\n\n/**\n * Search for a group in the global igmp_group_list\n *\n * @param ifp the network interface for which to look\n * @param addr the group ip address to search for\n * @return a struct igmp_group* if the group has been found,\n *         NULL if the group wasn't found.\n */\nstruct igmp_group *\nigmp_lookfor_group(struct netif *ifp, ip_addr_t *addr)\n{\n  struct igmp_group *group = igmp_group_list;\n\n  while (group != NULL) {\n    if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {\n      return group;\n    }\n    group = group->next;\n  }\n\n  /* to be clearer, we return NULL here instead of\n   * 'group' (which is also NULL at this point).\n   */\n  return NULL;\n}\n\n/**\n * Search for a specific igmp group and create a new one if not found-\n *\n * @param ifp the network interface for which to look\n * @param addr the group ip address to search\n * @return a struct igmp_group*,\n *         NULL on memory error.\n */\nstruct igmp_group *\nigmp_lookup_group(struct netif *ifp, ip_addr_t *addr)\n{\n  struct igmp_group *group = igmp_group_list;\n  \n  /* Search if the group already exists */\n  group = igmp_lookfor_group(ifp, addr);\n  if (group != NULL) {\n    /* Group already exists. */\n    return group;\n  }\n\n  /* Group doesn't exist yet, create a new one */\n  group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP);\n  if (group != NULL) {\n    group->netif              = ifp;\n    ip_addr_set(&(group->group_address), addr);\n    group->timer              = 0; /* Not running */\n    group->group_state        = IGMP_GROUP_NON_MEMBER;\n    group->last_reporter_flag = 0;\n    group->use                = 0;\n    group->next               = igmp_group_list;\n    \n    igmp_group_list = group;\n  }\n\n  LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_lookup_group: %sallocated a new group with address \", (group?\"\":\"impossible to \")));\n  ip_addr_debug_print(IGMP_DEBUG, addr);\n  LWIP_DEBUGF(IGMP_DEBUG, (\" on if %p\\n\", ifp));\n\n  return group;\n}\n\n/**\n * Remove a group in the global igmp_group_list\n *\n * @param group the group to remove from the global igmp_group_list\n * @return ERR_OK if group was removed from the list, an err_t otherwise\n */\nstatic err_t\nigmp_remove_group(struct igmp_group *group)\n{\n  err_t err = ERR_OK;\n\n  /* Is it the first group? */\n  if (igmp_group_list == group) {\n    igmp_group_list = group->next;\n  } else {\n    /* look for group further down the list */\n    struct igmp_group *tmpGroup;\n    for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {\n      if (tmpGroup->next == group) {\n        tmpGroup->next = group->next;\n        break;\n      }\n    }\n    /* Group not found in the global igmp_group_list */\n    if (tmpGroup == NULL)\n      err = ERR_ARG;\n  }\n  /* free group */\n  memp_free(MEMP_IGMP_GROUP, group);\n\n  return err;\n}\n\n/**\n * Called from ip_input() if a new IGMP packet is received.\n *\n * @param p received igmp packet, p->payload pointing to the ip header\n * @param inp network interface on which the packet was received\n * @param dest destination ip address of the igmp packet\n */\nvoid\nigmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)\n{\n  struct ip_hdr *    iphdr;\n  struct igmp_msg*   igmp;\n  struct igmp_group* group;\n  struct igmp_group* groupref;\n\n  IGMP_STATS_INC(igmp.recv);\n\n  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */    \n  iphdr = (struct ip_hdr *)p->payload;\n  if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {\n    pbuf_free(p);\n    IGMP_STATS_INC(igmp.lenerr);\n    LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: length error\\n\"));\n    return;\n  }\n\n  LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: message from \"));\n  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));\n  LWIP_DEBUGF(IGMP_DEBUG, (\" to address \"));\n  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));\n  LWIP_DEBUGF(IGMP_DEBUG, (\" on if %p\\n\", inp));\n\n  /* Now calculate and check the checksum */\n  igmp = (struct igmp_msg *)p->payload;\n  if (inet_chksum(igmp, p->len)) {\n    pbuf_free(p);\n    IGMP_STATS_INC(igmp.chkerr);\n    LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: checksum error\\n\"));\n    return;\n  }\n\n  /* Packet is ok so find an existing group */\n  group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */\n  \n  /* If group can be found or create... */\n  if (!group) {\n    pbuf_free(p);\n    IGMP_STATS_INC(igmp.drop);\n    LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: IGMP frame not for us\\n\"));\n    return;\n  }\n\n  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */\n  switch (igmp->igmp_msgtype) {\n   case IGMP_MEMB_QUERY: {\n     /* IGMP_MEMB_QUERY to the \"all systems\" address ? */\n     if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {\n       /* THIS IS THE GENERAL QUERY */\n       LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: General IGMP_MEMB_QUERY on \\\"ALL SYSTEMS\\\" address (224.0.0.1) [igmp_maxresp=%i]\\n\", (int)(igmp->igmp_maxresp)));\n\n       if (igmp->igmp_maxresp == 0) {\n         IGMP_STATS_INC(igmp.rx_v1);\n         LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\\n\"));\n         igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;\n       } else {\n         IGMP_STATS_INC(igmp.rx_general);\n       }\n\n       groupref = igmp_group_list;\n       while (groupref) {\n         /* Do not send messages on the all systems group address! */\n         if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {\n           igmp_delaying_member(groupref, igmp->igmp_maxresp);\n         }\n         groupref = groupref->next;\n       }\n     } else {\n       /* IGMP_MEMB_QUERY to a specific group ? */\n       if (!ip_addr_isany(&igmp->igmp_group_address)) {\n         LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: IGMP_MEMB_QUERY to a specific group \"));\n         ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);\n         if (ip_addr_cmp(dest, &allsystems)) {\n           ip_addr_t groupaddr;\n           LWIP_DEBUGF(IGMP_DEBUG, (\" using \\\"ALL SYSTEMS\\\" address (224.0.0.1) [igmp_maxresp=%i]\\n\", (int)(igmp->igmp_maxresp)));\n           /* we first need to re-look for the group since we used dest last time */\n           ip_addr_copy(groupaddr, igmp->igmp_group_address);\n           group = igmp_lookfor_group(inp, &groupaddr);\n         } else {\n           LWIP_DEBUGF(IGMP_DEBUG, (\" with the group address as destination [igmp_maxresp=%i]\\n\", (int)(igmp->igmp_maxresp)));\n         }\n\n         if (group != NULL) {\n           IGMP_STATS_INC(igmp.rx_group);\n           igmp_delaying_member(group, igmp->igmp_maxresp);\n         } else {\n           IGMP_STATS_INC(igmp.drop);\n         }\n       } else {\n         IGMP_STATS_INC(igmp.proterr);\n       }\n     }\n     break;\n   }\n   case IGMP_V2_MEMB_REPORT: {\n     LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: IGMP_V2_MEMB_REPORT\\n\"));\n     IGMP_STATS_INC(igmp.rx_report);\n     if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {\n       /* This is on a specific group we have already looked up */\n       group->timer = 0; /* stopped */\n       group->group_state = IGMP_GROUP_IDLE_MEMBER;\n       group->last_reporter_flag = 0;\n     }\n     break;\n   }\n   default: {\n     LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_input: unexpected msg %d in state %d on group %p on if %p\\n\",\n       igmp->igmp_msgtype, group->group_state, &group, group->netif));\n     IGMP_STATS_INC(igmp.proterr);\n     break;\n   }\n  }\n\n  pbuf_free(p);\n  return;\n}\n\n/**\n * Join a group on one network interface.\n *\n * @param ifaddr ip address of the network interface which should join a new group\n * @param groupaddr the ip address of the group which to join\n * @return ERR_OK if group was joined on the netif(s), an err_t otherwise\n */\nerr_t\nigmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)\n{\n  err_t              err = ERR_VAL; /* no matching interface */\n  struct igmp_group *group;\n  struct netif      *netif;\n\n  /* make sure it is multicast address */\n  LWIP_ERROR(\"igmp_joingroup: attempt to join non-multicast address\", ip_addr_ismulticast(groupaddr), return ERR_VAL;);\n  LWIP_ERROR(\"igmp_joingroup: attempt to join allsystems address\", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);\n\n  /* loop through netif's */\n  netif = netif_list;\n  while (netif != NULL) {\n    /* Should we join this interface ? */\n    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {\n      /* find group or create a new one if not found */\n      group = igmp_lookup_group(netif, groupaddr);\n\n      if (group != NULL) {\n        /* This should create a new group, check the state to make sure */\n        if (group->group_state != IGMP_GROUP_NON_MEMBER) {\n          LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\\n\"));\n        } else {\n          /* OK - it was new group */\n          LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_joingroup: join to new group: \"));\n          ip_addr_debug_print(IGMP_DEBUG, groupaddr);\n          LWIP_DEBUGF(IGMP_DEBUG, (\"\\n\"));\n\n          /* If first use of the group, allow the group at the MAC level */\n          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {\n            LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_joingroup: igmp_mac_filter(ADD \"));\n            ip_addr_debug_print(IGMP_DEBUG, groupaddr);\n            LWIP_DEBUGF(IGMP_DEBUG, (\") on if %p\\n\", netif));\n            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);\n          }\n\n          IGMP_STATS_INC(igmp.tx_join);\n          igmp_send(group, IGMP_V2_MEMB_REPORT);\n\n          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);\n\n          /* Need to work out where this timer comes from */\n          group->group_state = IGMP_GROUP_DELAYING_MEMBER;\n        }\n        /* Increment group use */\n        group->use++;\n        /* Join on this interface */\n        err = ERR_OK;\n      } else {\n        /* Return an error even if some network interfaces are joined */\n        /** @todo undo any other netif already joined */\n        LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_joingroup: Not enought memory to join to group\\n\"));\n        return ERR_MEM;\n      }\n    }\n    /* proceed to next network interface */\n    netif = netif->next;\n  }\n\n  return err;\n}\n\n/**\n * Leave a group on one network interface.\n *\n * @param ifaddr ip address of the network interface which should leave a group\n * @param groupaddr the ip address of the group which to leave\n * @return ERR_OK if group was left on the netif(s), an err_t otherwise\n */\nerr_t\nigmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr)\n{\n  err_t              err = ERR_VAL; /* no matching interface */\n  struct igmp_group *group;\n  struct netif      *netif;\n\n  /* make sure it is multicast address */\n  LWIP_ERROR(\"igmp_leavegroup: attempt to leave non-multicast address\", ip_addr_ismulticast(groupaddr), return ERR_VAL;);\n  LWIP_ERROR(\"igmp_leavegroup: attempt to leave allsystems address\", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);\n\n  /* loop through netif's */\n  netif = netif_list;\n  while (netif != NULL) {\n    /* Should we leave this interface ? */\n    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {\n      /* find group */\n      group = igmp_lookfor_group(netif, groupaddr);\n\n      if (group != NULL) {\n        /* Only send a leave if the flag is set according to the state diagram */\n        LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_leavegroup: Leaving group: \"));\n        ip_addr_debug_print(IGMP_DEBUG, groupaddr);\n        LWIP_DEBUGF(IGMP_DEBUG, (\"\\n\"));\n\n        /* If there is no other use of the group */\n        if (group->use <= 1) {\n          /* If we are the last reporter for this group */\n          if (group->last_reporter_flag) {\n            LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_leavegroup: sending leaving group\\n\"));\n            IGMP_STATS_INC(igmp.tx_leave);\n            igmp_send(group, IGMP_LEAVE_GROUP);\n          }\n          \n          /* Disable the group at the MAC level */\n          if (netif->igmp_mac_filter != NULL) {\n            LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_leavegroup: igmp_mac_filter(DEL \"));\n            ip_addr_debug_print(IGMP_DEBUG, groupaddr);\n            LWIP_DEBUGF(IGMP_DEBUG, (\") on if %p\\n\", netif));\n            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);\n          }\n          \n          LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_leavegroup: remove group: \"));\n          ip_addr_debug_print(IGMP_DEBUG, groupaddr);\n          LWIP_DEBUGF(IGMP_DEBUG, (\"\\n\"));          \n          \n          /* Free the group */\n          igmp_remove_group(group);\n        } else {\n          /* Decrement group use */\n          group->use--;\n        }\n        /* Leave on this interface */\n        err = ERR_OK;\n      } else {\n        /* It's not a fatal error on \"leavegroup\" */\n        LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_leavegroup: not member of group\\n\"));\n      }\n    }\n    /* proceed to next network interface */\n    netif = netif->next;\n  }\n\n  return err;\n}\n\n/**\n * The igmp timer function (both for NO_SYS=1 and =0)\n * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).\n */\nvoid\nigmp_tmr(void)\n{\n  struct igmp_group *group = igmp_group_list;\n\n  while (group != NULL) {\n    if (group->timer > 0) {\n      group->timer--;\n      if (group->timer == 0) {\n        igmp_timeout(group);\n      }\n    }\n    group = group->next;\n  }\n}\n\n/**\n * Called if a timeout for one group is reached.\n * Sends a report for this group.\n *\n * @param group an igmp_group for which a timeout is reached\n */\nstatic void\nigmp_timeout(struct igmp_group *group)\n{\n  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */\n  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {\n    LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_timeout: report membership for group with address \"));\n    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));\n    LWIP_DEBUGF(IGMP_DEBUG, (\" on if %p\\n\", group->netif));\n\n    IGMP_STATS_INC(igmp.tx_report);\n    igmp_send(group, IGMP_V2_MEMB_REPORT);\n  }\n}\n\n/**\n * Start a timer for an igmp group\n *\n * @param group the igmp_group for which to start a timer\n * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with\n *        every call to igmp_tmr())\n */\nstatic void\nigmp_start_timer(struct igmp_group *group, u8_t max_time)\n{\n  /* ensure the input value is > 0 */\n  if (max_time == 0) {\n    max_time = 1;\n  }\n  /* ensure the random value is > 0 */\n  group->timer = (LWIP_RAND() % (max_time - 1)) + 1;\n}\n\n/**\n * Stop a timer for an igmp_group\n *\n * @param group the igmp_group for which to stop the timer\n */\nstatic void\nigmp_stop_timer(struct igmp_group *group)\n{\n  group->timer = 0;\n}\n\n/**\n * Delaying membership report for a group if necessary\n *\n * @param group the igmp_group for which \"delaying\" membership report\n * @param maxresp query delay\n */\nstatic void\nigmp_delaying_member(struct igmp_group *group, u8_t maxresp)\n{\n  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||\n     ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&\n      ((group->timer == 0) || (maxresp < group->timer)))) {\n    igmp_start_timer(group, maxresp);\n    group->group_state = IGMP_GROUP_DELAYING_MEMBER;\n  }\n}\n\n\n/**\n * Sends an IP packet on a network interface. This function constructs the IP header\n * and calculates the IP header checksum. If the source IP address is NULL,\n * the IP address of the outgoing network interface is filled in as source address.\n *\n * @param p the packet to send (p->payload points to the data, e.g. next\n            protocol header; if dest == IP_HDRINCL, p already includes an IP\n            header and p->payload points to that IP header)\n * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\n *         IP  address of the netif used to send is used as source address)\n * @param dest the destination IP address to send the packet to\n * @param ttl the TTL value to be set in the IP header\n * @param proto the PROTOCOL to be set in the IP header\n * @param netif the netif on which to send this packet\n * @return ERR_OK if the packet was sent OK\n *         ERR_BUF if p doesn't have enough space for IP/LINK headers\n *         returns errors returned by netif->output\n */\nstatic err_t\nigmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif)\n{\n  /* This is the \"router alert\" option */\n  u16_t ra[2];\n  ra[0] = PP_HTONS(ROUTER_ALERT);\n  ra[1] = 0x0000; /* Router shall examine packet */\n  IGMP_STATS_INC(igmp.xmit);\n  return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);\n}\n\n/**\n * Send an igmp packet to a specific group.\n *\n * @param group the group to which to send the packet\n * @param type the type of igmp packet to send\n */\nstatic void\nigmp_send(struct igmp_group *group, u8_t type)\n{\n  struct pbuf*     p    = NULL;\n  struct igmp_msg* igmp = NULL;\n  ip_addr_t   src  = *IP_ADDR_ANY;\n  ip_addr_t*  dest = NULL;\n\n  /* IP header + \"router alert\" option + IGMP header */\n  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);\n  \n  if (p) {\n    igmp = (struct igmp_msg *)p->payload;\n    LWIP_ASSERT(\"igmp_send: check that first pbuf can hold struct igmp_msg\",\n               (p->len >= sizeof(struct igmp_msg)));\n    ip_addr_copy(src, group->netif->ip_addr);\n     \n    if (type == IGMP_V2_MEMB_REPORT) {\n      dest = &(group->group_address);\n      ip_addr_copy(igmp->igmp_group_address, group->group_address);\n      group->last_reporter_flag = 1; /* Remember we were the last to report */\n    } else {\n      if (type == IGMP_LEAVE_GROUP) {\n        dest = &allrouters;\n        ip_addr_copy(igmp->igmp_group_address, group->group_address);\n      }\n    }\n\n    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {\n      igmp->igmp_msgtype  = type;\n      igmp->igmp_maxresp  = 0;\n      igmp->igmp_checksum = 0;\n      igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);\n\n      igmp_ip_output_if(p, &src, dest, group->netif);\n    }\n\n    pbuf_free(p);\n  } else {\n    LWIP_DEBUGF(IGMP_DEBUG, (\"igmp_send: not enough memory for igmp_send\\n\"));\n    IGMP_STATS_INC(igmp.memerr);\n  }\n}\n\n#endif /* LWIP_IGMP */\n"
  },
  {
    "path": "app/lwip/core/ipv4/inet.c",
    "content": "/**\n * @file\n * Functions common to all TCP/IPv4 modules, such as the byte order functions.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/inet.h\"\n\n"
  },
  {
    "path": "app/lwip/core/ipv4/inet_chksum.c",
    "content": "/**\n * @file\n * Incluse internet checksum functions.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/inet_chksum.h\"\n#include \"lwip/def.h\"\n\n#include <stddef.h>\n#include <string.h>\n\n/* These are some reference implementations of the checksum algorithm, with the\n * aim of being simple, correct and fully portable. Checksumming is the\n * first thing you would want to optimize for your platform. If you create\n * your own version, link it in and in your cc.h put:\n * \n * #define LWIP_CHKSUM <your_checksum_routine> \n *\n * Or you can select from the implementations below by defining\n * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.\n */\n\n#ifndef LWIP_CHKSUM\n# define LWIP_CHKSUM lwip_standard_chksum\n# ifndef LWIP_CHKSUM_ALGORITHM\n#  define LWIP_CHKSUM_ALGORITHM 2\n# endif\n#endif\n/* If none set: */\n#ifndef LWIP_CHKSUM_ALGORITHM\n# define LWIP_CHKSUM_ALGORITHM 0\n#endif\n\n#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */\n/**\n * lwip checksum\n *\n * @param dataptr points to start of data to be summed at any boundary\n * @param len length of data to be summed\n * @return host order (!) lwip checksum (non-inverted Internet sum) \n *\n * @note accumulator size limits summable length to 64k\n * @note host endianess is irrelevant (p3 RFC1071)\n */\nstatic u16_t ICACHE_FLASH_ATTR\nlwip_standard_chksum(void *dataptr, u16_t len)\n{\n  u32_t acc;\n  u16_t src;\n  u8_t *octetptr;\n\n  acc = 0;\n  /* dataptr may be at odd or even addresses */\n  octetptr = (u8_t*)dataptr;\n  while (len > 1) {\n    /* declare first octet as most significant\n       thus assume network order, ignoring host order */\n    src = (*octetptr) << 8;\n    octetptr++;\n    /* declare second octet as least significant */\n    src |= (*octetptr);\n    octetptr++;\n    acc += src;\n    len -= 2;\n  }\n  if (len > 0) {\n    /* accumulate remaining octet */\n    src = (*octetptr) << 8;\n    acc += src;\n  }\n  /* add deferred carry bits */\n  acc = (acc >> 16) + (acc & 0x0000ffffUL);\n  if ((acc & 0xffff0000UL) != 0) {\n    acc = (acc >> 16) + (acc & 0x0000ffffUL);\n  }\n  /* This maybe a little confusing: reorder sum using htons()\n     instead of ntohs() since it has a little less call overhead.\n     The caller must invert bits for Internet sum ! */\n  return htons((u16_t)acc);\n}\n#endif\n\n#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */\n/*\n * Curt McDowell\n * Broadcom Corp.\n * csm@broadcom.com\n *\n * IP checksum two bytes at a time with support for\n * unaligned buffer.\n * Works for len up to and including 0x20000.\n * by Curt McDowell, Broadcom Corp. 12/08/2005\n *\n * @param dataptr points to start of data to be summed at any boundary\n * @param len length of data to be summed\n * @return host order (!) lwip checksum (non-inverted Internet sum) \n */\n\nstatic u16_t ICACHE_FLASH_ATTR\nlwip_standard_chksum(void *dataptr, int len)\n{\n  u8_t *pb = (u8_t *)dataptr;\n  u16_t *ps, t = 0;\n  u32_t sum = 0;\n  int odd = ((mem_ptr_t)pb & 1);\n\n  /* Get aligned to u16_t */\n  if (odd && len > 0) {\n    ((u8_t *)&t)[1] = *pb++;\n    len--;\n  }\n\n  /* Add the bulk of the data */\n  ps = (u16_t *)(void *)pb;\n  while (len > 1) {\n    sum += *ps++;\n    len -= 2;\n  }\n\n  /* Consume left-over byte, if any */\n  if (len > 0) {\n    ((u8_t *)&t)[0] = *(u8_t *)ps;\n  }\n\n  /* Add end bytes */\n  sum += t;\n\n  /* Fold 32-bit sum to 16 bits\n     calling this twice is propably faster than if statements... */\n  sum = FOLD_U32T(sum);\n  sum = FOLD_U32T(sum);\n\n  /* Swap if alignment was odd */\n  if (odd) {\n    sum = SWAP_BYTES_IN_WORD(sum);\n  }\n\n  return (u16_t)sum;\n}\n#endif\n\n#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */\n/**\n * An optimized checksum routine. Basically, it uses loop-unrolling on\n * the checksum loop, treating the head and tail bytes specially, whereas\n * the inner loop acts on 8 bytes at a time. \n *\n * @arg start of buffer to be checksummed. May be an odd byte address.\n * @len number of bytes in the buffer to be checksummed.\n * @return host order (!) lwip checksum (non-inverted Internet sum) \n * \n * by Curt McDowell, Broadcom Corp. December 8th, 2005\n */\n\nstatic u16_t ICACHE_FLASH_ATTR\nlwip_standard_chksum(void *dataptr, int len)\n{\n  u8_t *pb = (u8_t *)dataptr;\n  u16_t *ps, t = 0;\n  u32_t *pl;\n  u32_t sum = 0, tmp;\n  /* starts at odd byte address? */\n  int odd = ((mem_ptr_t)pb & 1);\n\n  if (odd && len > 0) {\n    ((u8_t *)&t)[1] = *pb++;\n    len--;\n  }\n\n  ps = (u16_t *)pb;\n\n  if (((mem_ptr_t)ps & 3) && len > 1) {\n    sum += *ps++;\n    len -= 2;\n  }\n\n  pl = (u32_t *)ps;\n\n  while (len > 7)  {\n    tmp = sum + *pl++;          /* ping */\n    if (tmp < sum) {\n      tmp++;                    /* add back carry */\n    }\n\n    sum = tmp + *pl++;          /* pong */\n    if (sum < tmp) {\n      sum++;                    /* add back carry */\n    }\n\n    len -= 8;\n  }\n\n  /* make room in upper bits */\n  sum = FOLD_U32T(sum);\n\n  ps = (u16_t *)pl;\n\n  /* 16-bit aligned word remaining? */\n  while (len > 1) {\n    sum += *ps++;\n    len -= 2;\n  }\n\n  /* dangling tail byte remaining? */\n  if (len > 0) {                /* include odd byte */\n    ((u8_t *)&t)[0] = *(u8_t *)ps;\n  }\n\n  sum += t;                     /* add end bytes */\n\n  /* Fold 32-bit sum to 16 bits\n     calling this twice is propably faster than if statements... */\n  sum = FOLD_U32T(sum);\n  sum = FOLD_U32T(sum);\n\n  if (odd) {\n    sum = SWAP_BYTES_IN_WORD(sum);\n  }\n\n  return (u16_t)sum;\n}\n#endif\n\n/* inet_chksum_pseudo:\n *\n * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.\n * IP addresses are expected to be in network byte order.\n *\n * @param p chain of pbufs over that a checksum should be calculated (ip data part)\n * @param src source ip address (used for checksum of pseudo header)\n * @param dst destination ip address (used for checksum of pseudo header)\n * @param proto ip protocol (used for checksum of pseudo header)\n * @param proto_len length of the ip data part (used for checksum of pseudo header)\n * @return checksum (as u16_t) to be saved directly in the protocol header\n */\nu16_t\ninet_chksum_pseudo(struct pbuf *p,\n       ip_addr_t *src, ip_addr_t *dest,\n       u8_t proto, u16_t proto_len)\n{\n  u32_t acc;\n  u32_t addr;\n  struct pbuf *q;\n  u8_t swapped;\n\n  acc = 0;\n  swapped = 0;\n  /* iterate through all pbuf in chain */\n  for(q = p; q != NULL; q = q->next) {\n    LWIP_DEBUGF(INET_DEBUG, (\"inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \\n\",\n      (void *)q, (void *)q->next));\n    acc += LWIP_CHKSUM(q->payload, q->len);\n    /*LWIP_DEBUGF(INET_DEBUG, (\"inet_chksum_pseudo(): unwrapped lwip_chksum()=%\"X32_F\" \\n\", acc));*/\n    /* just executing this next line is probably faster that the if statement needed\n       to check whether we really need to execute it, and does no harm */\n    acc = FOLD_U32T(acc);\n    if (q->len % 2 != 0) {\n      swapped = 1 - swapped;\n      acc = SWAP_BYTES_IN_WORD(acc);\n    }\n    /*LWIP_DEBUGF(INET_DEBUG, (\"inet_chksum_pseudo(): wrapped lwip_chksum()=%\"X32_F\" \\n\", acc));*/\n  }\n\n  if (swapped) {\n    acc = SWAP_BYTES_IN_WORD(acc);\n  }\n  addr = ip4_addr_get_u32(src);\n  acc += (addr & 0xffffUL);\n  acc += ((addr >> 16) & 0xffffUL);\n  addr = ip4_addr_get_u32(dest);\n  acc += (addr & 0xffffUL);\n  acc += ((addr >> 16) & 0xffffUL);\n  acc += (u32_t)htons((u16_t)proto);\n  acc += (u32_t)htons(proto_len);\n\n  /* Fold 32-bit sum to 16 bits\n     calling this twice is propably faster than if statements... */\n  acc = FOLD_U32T(acc);\n  acc = FOLD_U32T(acc);\n  LWIP_DEBUGF(INET_DEBUG, (\"inet_chksum_pseudo(): pbuf chain lwip_chksum()=%\"X32_F\"\\n\", acc));\n  return (u16_t)~(acc & 0xffffUL);\n}\n\n/* inet_chksum_pseudo:\n *\n * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.\n * IP addresses are expected to be in network byte order.\n *\n * @param p chain of pbufs over that a checksum should be calculated (ip data part)\n * @param src source ip address (used for checksum of pseudo header)\n * @param dst destination ip address (used for checksum of pseudo header)\n * @param proto ip protocol (used for checksum of pseudo header)\n * @param proto_len length of the ip data part (used for checksum of pseudo header)\n * @return checksum (as u16_t) to be saved directly in the protocol header\n */\nu16_t\ninet_chksum_pseudo_partial(struct pbuf *p,\n       ip_addr_t *src, ip_addr_t *dest,\n       u8_t proto, u16_t proto_len, u16_t chksum_len)\n{\n  u32_t acc;\n  u32_t addr;\n  struct pbuf *q;\n  u8_t swapped;\n  u16_t chklen;\n\n  acc = 0;\n  swapped = 0;\n  /* iterate through all pbuf in chain */\n  for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {\n    LWIP_DEBUGF(INET_DEBUG, (\"inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \\n\",\n      (void *)q, (void *)q->next));\n    chklen = q->len;\n    if (chklen > chksum_len) {\n      chklen = chksum_len;\n    }\n    acc += LWIP_CHKSUM(q->payload, chklen);\n    chksum_len -= chklen;\n    LWIP_ASSERT(\"delete me\", chksum_len < 0x7fff);\n    /*LWIP_DEBUGF(INET_DEBUG, (\"inet_chksum_pseudo(): unwrapped lwip_chksum()=%\"X32_F\" \\n\", acc));*/\n    /* fold the upper bit down */\n    acc = FOLD_U32T(acc);\n    if (q->len % 2 != 0) {\n      swapped = 1 - swapped;\n      acc = SWAP_BYTES_IN_WORD(acc);\n    }\n    /*LWIP_DEBUGF(INET_DEBUG, (\"inet_chksum_pseudo(): wrapped lwip_chksum()=%\"X32_F\" \\n\", acc));*/\n  }\n\n  if (swapped) {\n    acc = SWAP_BYTES_IN_WORD(acc);\n  }\n  addr = ip4_addr_get_u32(src);\n  acc += (addr & 0xffffUL);\n  acc += ((addr >> 16) & 0xffffUL);\n  addr = ip4_addr_get_u32(dest);\n  acc += (addr & 0xffffUL);\n  acc += ((addr >> 16) & 0xffffUL);\n  acc += (u32_t)htons((u16_t)proto);\n  acc += (u32_t)htons(proto_len);\n\n  /* Fold 32-bit sum to 16 bits\n     calling this twice is propably faster than if statements... */\n  acc = FOLD_U32T(acc);\n  acc = FOLD_U32T(acc);\n  LWIP_DEBUGF(INET_DEBUG, (\"inet_chksum_pseudo(): pbuf chain lwip_chksum()=%\"X32_F\"\\n\", acc));\n  return (u16_t)~(acc & 0xffffUL);\n}\n\n/* inet_chksum:\n *\n * Calculates the Internet checksum over a portion of memory. Used primarily for IP\n * and ICMP.\n *\n * @param dataptr start of the buffer to calculate the checksum (no alignment needed)\n * @param len length of the buffer to calculate the checksum\n * @return checksum (as u16_t) to be saved directly in the protocol header\n */\n\nu16_t\ninet_chksum(void *dataptr, u16_t len)\n{\n  return ~LWIP_CHKSUM(dataptr, len);\n}\n\n/**\n * Calculate a checksum over a chain of pbufs (without pseudo-header, much like\n * inet_chksum only pbufs are used).\n *\n * @param p pbuf chain over that the checksum should be calculated\n * @return checksum (as u16_t) to be saved directly in the protocol header\n */\nu16_t\ninet_chksum_pbuf(struct pbuf *p)\n{\n  u32_t acc;\n  struct pbuf *q;\n  u8_t swapped;\n\n  acc = 0;\n  swapped = 0;\n  for(q = p; q != NULL; q = q->next) {\n    acc += LWIP_CHKSUM(q->payload, q->len);\n    acc = FOLD_U32T(acc);\n    if (q->len % 2 != 0) {\n      swapped = 1 - swapped;\n      acc = SWAP_BYTES_IN_WORD(acc);\n    }\n  }\n\n  if (swapped) {\n    acc = SWAP_BYTES_IN_WORD(acc);\n  }\n  return (u16_t)~(acc & 0xffffUL);\n}\n\n/* These are some implementations for LWIP_CHKSUM_COPY, which copies data\n * like MEMCPY but generates a checksum at the same time. Since this is a\n * performance-sensitive function, you might want to create your own version\n * in assembly targeted at your hardware by defining it in lwipopts.h:\n *   #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len)\n */\n\n#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */\n/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM.\n * For architectures with big caches, data might still be in cache when\n * generating the checksum after copying.\n */\nu16_t\nlwip_chksum_copy(void *dst, const void *src, u16_t len)\n{\n  MEMCPY(dst, src, len);\n  return LWIP_CHKSUM(dst, len);\n}\n#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */\n"
  },
  {
    "path": "app/lwip/core/ipv4/ip.c",
    "content": "/**\n * @file\n * This is the IPv4 layer implementation for incoming and outgoing IP traffic.\n * \n * @see ip_frag.c\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/def.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/ip_frag.h\"\n#include \"lwip/inet_chksum.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/icmp.h\"\n#include \"lwip/igmp.h\"\n#include \"lwip/raw.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/tcp_impl.h\"\n#include \"lwip/snmp.h\"\n#include \"lwip/dhcp.h\"\n#include \"lwip/autoip.h\"\n#include \"lwip/stats.h\"\n#include \"arch/perf.h\"\n\n#include <string.h>\n\n/** Set this to 0 in the rare case of wanting to call an extra function to\n * generate the IP checksum (in contrast to calculating it on-the-fly). */\n#ifndef LWIP_INLINE_IP_CHKSUM\n#define LWIP_INLINE_IP_CHKSUM   1\n#endif\n#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP\n#define CHECKSUM_GEN_IP_INLINE  1\n#else\n#define CHECKSUM_GEN_IP_INLINE  0\n#endif\n\n#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)\n#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1\n\n/** Some defines for DHCP to let link-layer-addressed packets through while the\n * netif is down.\n * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT\n * to return 1 if the port is accepted and 0 if the port is not accepted.\n */\n#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)\n/* accept DHCP client port and custom port */\n#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \\\n         || (LWIP_IP_ACCEPT_UDP_PORT(port)))\n#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */\n/* accept custom port only */\n#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port))\n#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */\n/* accept DHCP client port only */\n#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))\n#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */\n\n#else /* LWIP_DHCP */\n#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0\n#endif /* LWIP_DHCP */\n\n/**\n * The interface that provided the packet for the current callback\n * invocation.\n */\nstruct netif *current_netif;\n\n/**\n * Header of the input packet currently being processed.\n */\nconst struct ip_hdr *current_header;\n/** Source IP address of current_header */\nip_addr_t current_iphdr_src;\n/** Destination IP address of current_header */\nip_addr_t current_iphdr_dest;\n\n/** The IP header ID of the next outgoing IP packet */\nstatic u16_t ip_id;\n\n/**\n * Finds the appropriate network interface for a given IP address. It\n * searches the list of network interfaces linearly. A match is found\n * if the masked IP address of the network interface equals the masked\n * IP address given to the function.\n *\n * @param dest the destination IP address for which to find the route\n * @return the netif on which to send to reach dest\n */\nstruct netif *\nip_route(ip_addr_t *dest)\n{\n  struct netif *netif;\n\n  /* iterate through netifs */\n  for(netif = netif_list; netif != NULL; netif = netif->next) {\n    /* network mask matches? */\n    if (netif_is_up(netif)) {\n      if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {\n        /* return netif on which to forward IP packet */\n        return netif;\n      }\n    }\n  }\n  /* iterate through netifs */\n  for(netif = netif_list; netif != NULL; netif = netif->next) {\n    /* network mask matches? */\n    if (netif_is_up(netif)) {\n      if (!ip_addr_isbroadcast(dest, netif) && netif == (struct netif *)eagle_lwip_getif(0)) {\n        return netif;\n      }\n    }\n  }\n  if ((netif_default == NULL) || (!netif_is_up(netif_default))) {\n    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"ip_route: No route to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));\n    IP_STATS_INC(ip.rterr);\n    snmp_inc_ipoutnoroutes();\n    return NULL;\n  }\n  /* no matching netif found, use default netif */\n  return netif_default;\n}\n\n/**\n * Finds the appropriate network interface for a source IP address. It\n * searches the list of network interfaces linearly. A match is found\n * if the masked IP address of the network interface equals the masked\n * IP address given to the function.\n *\n * @param source the sourcination IP address for which to find the route\n * @return the netif on which to send to reach source\n */\n\nstruct netif *ICACHE_FLASH_ATTR\nip_router(ip_addr_t *dest, ip_addr_t *source){\n\tstruct netif *netif;\n\t/* iterate through netifs */\n  \tfor(netif = netif_list; netif != NULL; netif = netif->next) {\n\t    /* network mask matches? */\n\t\t\n\t\tif (netif_is_up(netif)) {\n\t      if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {\n\t        /* return netif on which to forward IP packet */\n\t        return netif;\n\t      }\n\t    }\n\n\t\tif (netif_is_up(netif)) {\n\t      if (ip_addr_netcmp(source, &(netif->ip_addr), &(netif->netmask))) {\n\t        /* return netif on which to forward IP packet */\n\t        return netif;\n\t      }\n\t    }\n  \t}\n\n\tif ((netif_default == NULL) || (!netif_is_up(netif_default))) {\n\t    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"ip_route: No route to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n\t      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));\n\t    IP_STATS_INC(ip.rterr);\n\t    snmp_inc_ipoutnoroutes();\n\t    return NULL;\n  \t}\n  \t/* no matching netif found, use default netif */\n  \tos_printf(\"ip_router %d %p\\n\", __LINE__, netif_default);\n  \treturn netif_default;\n}\n\n#if IP_FORWARD\n/**\n * Forwards an IP packet. It finds an appropriate route for the\n * packet, decrements the TTL value of the packet, adjusts the\n * checksum and outputs the packet on the appropriate interface.\n *\n * @param p the packet to forward (p->payload points to IP header)\n * @param iphdr the IP header of the input packet\n * @param inp the netif on which this packet was received\n */\nstatic void ICACHE_FLASH_ATTR\nip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)\n{\n  struct netif *netif;\n\n  PERF_START;\n\n  /* RFC3927 2.7: do not forward link-local addresses */\n  if (ip_addr_islinklocal(&current_iphdr_dest)) {\n    LWIP_DEBUGF(IP_DEBUG, (\"ip_forward: not forwarding LLA %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n      ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),\n      ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));\n    goto return_noroute;\n  }\n\n  /* Find network interface where to forward this IP packet to. */\n  netif = ip_route(&current_iphdr_dest);\n  if (netif == NULL) {\n    LWIP_DEBUGF(IP_DEBUG, (\"ip_forward: no forwarding route for %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\" found\\n\",\n      ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),\n      ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));\n    goto return_noroute;\n  }\n  /* Do not forward packets onto the same network interface on which\n   * they arrived. */\n  if (netif == inp) {\n    LWIP_DEBUGF(IP_DEBUG, (\"ip_forward: not bouncing packets back on incoming interface.\\n\"));\n    goto return_noroute;\n  }\n\n  /* decrement TTL */\n  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);\n  /* send ICMP if TTL == 0 */\n  if (IPH_TTL(iphdr) == 0) {\n    snmp_inc_ipinhdrerrors();\n#if LWIP_ICMP\n    /* Don't send ICMP messages in response to ICMP messages */\n    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {\n      icmp_time_exceeded(p, ICMP_TE_TTL);\n    }\n#endif /* LWIP_ICMP */\n    return;\n  }\n\n  /* Incrementally update the IP checksum. */\n  if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) {\n    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);\n  } else {\n    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));\n  }\n\n  LWIP_DEBUGF(IP_DEBUG, (\"ip_forward: forwarding packet to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n    ip4_addr1_16(&current_iphdr_dest), ip4_addr2_16(&current_iphdr_dest),\n    ip4_addr3_16(&current_iphdr_dest), ip4_addr4_16(&current_iphdr_dest)));\n\n  IP_STATS_INC(ip.fw);\n  IP_STATS_INC(ip.xmit);\n  snmp_inc_ipforwdatagrams();\n\n  PERF_STOP(\"ip_forward\");\n  /* transmit pbuf on chosen interface */\n  netif->output(netif, p, &current_iphdr_dest);\n  return;\nreturn_noroute:\n  snmp_inc_ipoutnoroutes();\n}\n#endif /* IP_FORWARD */\n\n/**\n * This function is called by the network interface device driver when\n * an IP packet is received. The function does the basic checks of the\n * IP header such as packet size being at least larger than the header\n * size etc. If the packet was not destined for us, the packet is\n * forwarded (using ip_forward). The IP checksum is always checked.\n *\n * Finally, the packet is sent to the upper layer protocol input function.\n * \n * @param p the received IP packet (p->payload points to IP header)\n * @param inp the netif on which this packet was received\n * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't\n *         processed, but currently always returns ERR_OK)\n */\nerr_t\nip_input(struct pbuf *p, struct netif *inp)\n{\n  struct ip_hdr *iphdr;\n  struct netif *netif;\n  u16_t iphdr_hlen;\n  u16_t iphdr_len;\n#if IP_ACCEPT_LINK_LAYER_ADDRESSING\n  int check_ip_src=1;\n#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */\n\n  IP_STATS_INC(ip.recv);\n  snmp_inc_ipinreceives();\n\n  /* identify the IP header */\n  iphdr = (struct ip_hdr *)p->payload;\n  if (IPH_V(iphdr) != 4) {\n    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, (\"IP packet dropped due to bad version number %\"U16_F\"\\n\", IPH_V(iphdr)));\n    ip_debug_print(p);\n    pbuf_free(p);\n    IP_STATS_INC(ip.err);\n    IP_STATS_INC(ip.drop);\n    snmp_inc_ipinhdrerrors();\n    return ERR_OK;\n  }\n\n  /* obtain IP header length in number of 32-bit words */\n  iphdr_hlen = IPH_HL(iphdr);\n  /* calculate IP header length in bytes */\n  iphdr_hlen *= 4;\n  /* obtain ip length in bytes */\n  iphdr_len = ntohs(IPH_LEN(iphdr));\n\n  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */\n  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {\n    if (iphdr_hlen > p->len) {\n      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n        (\"IP header (len %\"U16_F\") does not fit in first pbuf (len %\"U16_F\"), IP packet dropped.\\n\",\n        iphdr_hlen, p->len));\n    }\n    if (iphdr_len > p->tot_len) {\n      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n        (\"IP (len %\"U16_F\") is longer than pbuf (len %\"U16_F\"), IP packet dropped.\\n\",\n        iphdr_len, p->tot_len));\n    }\n    /* free (drop) packet pbufs */\n    pbuf_free(p);\n    IP_STATS_INC(ip.lenerr);\n    IP_STATS_INC(ip.drop);\n    snmp_inc_ipindiscards();\n    return ERR_OK;\n  }\n\n  /* verify checksum */\n#if CHECKSUM_CHECK_IP\n  if (inet_chksum(iphdr, iphdr_hlen) != 0) {\n\n    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n      (\"Checksum (0x%\"X16_F\") failed, IP packet dropped.\\n\", inet_chksum(iphdr, iphdr_hlen)));\n    ip_debug_print(p);\n    pbuf_free(p);\n    IP_STATS_INC(ip.chkerr);\n    IP_STATS_INC(ip.drop);\n    snmp_inc_ipinhdrerrors();\n    return ERR_OK;\n  }\n#endif\n\n  /* Trim pbuf. This should have been done at the netif layer,\n   * but we'll do it anyway just to be sure that its done. */\n  pbuf_realloc(p, iphdr_len);\n\n  /* copy IP addresses to aligned ip_addr_t */\n  ip_addr_copy(current_iphdr_dest, iphdr->dest);\n  ip_addr_copy(current_iphdr_src, iphdr->src);\n\n  /* match packet against an interface, i.e. is this packet for us? */\n#if LWIP_IGMP\n  if (ip_addr_ismulticast(&current_iphdr_dest)) {\n    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &current_iphdr_dest))) {\n      netif = inp;\n    } else {\n      netif = NULL;\n    }\n  } else\n#endif /* LWIP_IGMP */\n  {\n    /* start trying with inp. if that's not acceptable, start walking the\n       list of configured netifs.\n       'first' is used as a boolean to mark whether we started walking the list */\n    int first = 1;\n    netif = inp;\n    do {\n      LWIP_DEBUGF(IP_DEBUG, (\"ip_input: iphdr->dest 0x%\"X32_F\" netif->ip_addr 0x%\"X32_F\" (0x%\"X32_F\", 0x%\"X32_F\", 0x%\"X32_F\")\\n\",\n          ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr),\n          ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask),\n          ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask),\n          ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask)));\n\n      /* interface is up and configured? */\n      if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {\n        /* unicast to this interface address? */\n        if (ip_addr_cmp(&current_iphdr_dest, &(netif->ip_addr)) ||\n            /* or broadcast on this interface network address? */\n            ip_addr_isbroadcast(&current_iphdr_dest, netif)) {\n          LWIP_DEBUGF(IP_DEBUG, (\"ip_input: packet accepted on interface %c%c\\n\",\n              netif->name[0], netif->name[1]));\n          /* break out of for loop */\n          break;\n        }\n#if LWIP_AUTOIP\n        /* connections to link-local addresses must persist after changing\n           the netif's address (RFC3927 ch. 1.9) */\n        if ((netif->autoip != NULL) &&\n            ip_addr_cmp(&current_iphdr_dest, &(netif->autoip->llipaddr))) {\n          LWIP_DEBUGF(IP_DEBUG, (\"ip_input: LLA packet accepted on interface %c%c\\n\",\n              netif->name[0], netif->name[1]));\n          /* break out of for loop */\n          break;\n        }\n#endif /* LWIP_AUTOIP */\n      }\n      if (first) {\n        first = 0;\n        netif = netif_list;\n      } else {\n        netif = netif->next;\n      }\n      if (netif == inp) {\n        netif = netif->next;\n      }\n    } while(netif != NULL);\n  }\n\n#if IP_ACCEPT_LINK_LAYER_ADDRESSING\n  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed\n   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.\n   * According to RFC 1542 section 3.1.1, referred by RFC 2131).\n   *\n   * If you want to accept private broadcast communication while a netif is down,\n   * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:\n   *\n   * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))\n   */\n  if (netif == NULL) {\n    /* remote port is DHCP server? */\n    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {\n      struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);\n      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, (\"ip_input: UDP packet to DHCP client port %\"U16_F\"\\n\",\n        ntohs(udphdr->dest)));\n      if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {\n        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, (\"ip_input: DHCP packet accepted.\\n\"));\n        netif = inp;\n        check_ip_src = 0;\n      }\n    }\n  }\n#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */\n\n  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */\n#if IP_ACCEPT_LINK_LAYER_ADDRESSING\n  /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */\n  if (check_ip_src && !ip_addr_isany(&current_iphdr_src))\n#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */\n  {  if ((ip_addr_isbroadcast(&current_iphdr_src, inp)) ||\n         (ip_addr_ismulticast(&current_iphdr_src))) {\n      /* packet source is not valid */\n      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, (\"ip_input: packet source is not valid.\\n\"));\n      /* free (drop) packet pbufs */\n      pbuf_free(p);\n      IP_STATS_INC(ip.drop);\n      snmp_inc_ipinaddrerrors();\n      snmp_inc_ipindiscards();\n      return ERR_OK;\n    }\n  }\n\n  /* packet not for us? */\n  if (netif == NULL) {\n    /* packet not for us, route or discard */\n    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, (\"ip_input: packet not for us.\\n\"));\n#if IP_FORWARD\n    /* non-broadcast packet? */\n    if (!ip_addr_isbroadcast(&current_iphdr_dest, inp)) {\n      /* try to forward IP packet on (other) interfaces */\n      ip_forward(p, iphdr, inp);\n    } else\n#endif /* IP_FORWARD */\n    {\n      snmp_inc_ipinaddrerrors();\n      snmp_inc_ipindiscards();\n    }\n    pbuf_free(p);\n    return ERR_OK;\n  }\n  /* packet consists of multiple fragments? */\n  if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {\n#if IP_REASSEMBLY /* packet fragment reassembly code present? */\n    LWIP_DEBUGF(IP_DEBUG, (\"IP packet is a fragment (id=0x%04\"X16_F\" tot_len=%\"U16_F\" len=%\"U16_F\" MF=%\"U16_F\" offset=%\"U16_F\"), calling ip_reass()\\n\",\n      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));\n    /* reassemble the packet*/\n    p = ip_reass(p);\n    /* packet not fully reassembled yet? */\n    if (p == NULL) {\n      return ERR_OK;\n    }\n    iphdr = (struct ip_hdr *)p->payload;\n#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */\n    pbuf_free(p);\n    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"IP packet dropped since it was fragmented (0x%\"X16_F\") (while IP_REASSEMBLY == 0).\\n\",\n      ntohs(IPH_OFFSET(iphdr))));\n    IP_STATS_INC(ip.opterr);\n    IP_STATS_INC(ip.drop);\n    /* unsupported protocol feature */\n    snmp_inc_ipinunknownprotos();\n    return ERR_OK;\n#endif /* IP_REASSEMBLY */\n  }\n\n#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */\n\n#if LWIP_IGMP\n  /* there is an extra \"router alert\" option in IGMP messages which we allow for but do not police */\n  if((iphdr_hlen > IP_HLEN) &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {\n#else\n  if (iphdr_hlen > IP_HLEN) {\n#endif /* LWIP_IGMP */\n    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\\n\"));\n    pbuf_free(p);\n    IP_STATS_INC(ip.opterr);\n    IP_STATS_INC(ip.drop);\n    /* unsupported protocol feature */\n    snmp_inc_ipinunknownprotos();\n    return ERR_OK;\n  }\n#endif /* IP_OPTIONS_ALLOWED == 0 */\n\n  /* send to upper layers */\n  LWIP_DEBUGF(IP_DEBUG, (\"ip_input: \\n\"));\n  ip_debug_print(p);\n  LWIP_DEBUGF(IP_DEBUG, (\"ip_input: p->len %\"U16_F\" p->tot_len %\"U16_F\"\\n\", p->len, p->tot_len));\n\n  current_netif = inp;\n  current_header = iphdr;\n\n#if LWIP_RAW\n  /* raw input did not eat the packet? */\n  if (raw_input(p, inp) == 0)\n#endif /* LWIP_RAW */\n  {\n\n    switch (IPH_PROTO(iphdr)) {\n#if LWIP_UDP\n    case IP_PROTO_UDP:\n#if LWIP_UDPLITE\n    case IP_PROTO_UDPLITE:\n#endif /* LWIP_UDPLITE */\n      snmp_inc_ipindelivers();\n      udp_input(p, inp);\n      break;\n#endif /* LWIP_UDP */\n#if LWIP_TCP\n    case IP_PROTO_TCP:\n      snmp_inc_ipindelivers();\n      tcp_input(p, inp);\n      break;\n#endif /* LWIP_TCP */\n#if LWIP_ICMP\n    case IP_PROTO_ICMP:\n      snmp_inc_ipindelivers();\n      icmp_input(p, inp);\n      break;\n#endif /* LWIP_ICMP */\n#if LWIP_IGMP\n    case IP_PROTO_IGMP:\n      igmp_input(p, inp, &current_iphdr_dest);\n      break;\n#endif /* LWIP_IGMP */\n    default:\n#if LWIP_ICMP\n      /* send ICMP destination protocol unreachable unless is was a broadcast */\n      if (!ip_addr_isbroadcast(&current_iphdr_dest, inp) &&\n          !ip_addr_ismulticast(&current_iphdr_dest)) {\n        p->payload = iphdr;\n        icmp_dest_unreach(p, ICMP_DUR_PROTO);\n      }\n#endif /* LWIP_ICMP */\n      pbuf_free(p);\n\n      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"Unsupported transport protocol %\"U16_F\"\\n\", IPH_PROTO(iphdr)));\n\n      IP_STATS_INC(ip.proterr);\n      IP_STATS_INC(ip.drop);\n      snmp_inc_ipinunknownprotos();\n    }\n  }\n\n  current_netif = NULL;\n  current_header = NULL;\n  ip_addr_set_any(&current_iphdr_src);\n  ip_addr_set_any(&current_iphdr_dest);\n\n  return ERR_OK;\n}\n\n/**\n * Sends an IP packet on a network interface. This function constructs\n * the IP header and calculates the IP header checksum. If the source\n * IP address is NULL, the IP address of the outgoing network\n * interface is filled in as source address.\n * If the destination IP address is IP_HDRINCL, p is assumed to already\n * include an IP header and p->payload points to it instead of the data.\n *\n * @param p the packet to send (p->payload points to the data, e.g. next\n            protocol header; if dest == IP_HDRINCL, p already includes an IP\n            header and p->payload points to that IP header)\n * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\n *         IP  address of the netif used to send is used as source address)\n * @param dest the destination IP address to send the packet to\n * @param ttl the TTL value to be set in the IP header\n * @param tos the TOS value to be set in the IP header\n * @param proto the PROTOCOL to be set in the IP header\n * @param netif the netif on which to send this packet\n * @return ERR_OK if the packet was sent OK\n *         ERR_BUF if p doesn't have enough space for IP/LINK headers\n *         returns errors returned by netif->output\n *\n * @note ip_id: RFC791 \"some host may be able to simply use\n *  unique identifiers independent of destination\"\n */\nerr_t\nip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,\n             u8_t ttl, u8_t tos,\n             u8_t proto, struct netif *netif)\n{\n#if IP_OPTIONS_SEND\n  return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);\n}\n\n/**\n * Same as ip_output_if() but with the possibility to include IP options:\n *\n * @ param ip_options pointer to the IP options, copied into the IP header\n * @ param optlen length of ip_options\n */\nerr_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,\n       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,\n       u16_t optlen)\n{\n#endif /* IP_OPTIONS_SEND */\n  struct ip_hdr *iphdr;\n  ip_addr_t dest_addr;\n#if CHECKSUM_GEN_IP_INLINE\n  u32_t chk_sum = 0;\n#endif /* CHECKSUM_GEN_IP_INLINE */\n\n  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer\n     gets altered as the packet is passed down the stack */\n  LWIP_ASSERT(\"p->ref == 1\", p->ref == 1);\n\n  snmp_inc_ipoutrequests();\n\n  /* Should the IP header be generated or is it already included in p? */\n  if (dest != IP_HDRINCL) {\n    u16_t ip_hlen = IP_HLEN;\n#if IP_OPTIONS_SEND\n    u16_t optlen_aligned = 0;\n    if (optlen != 0) {\n#if CHECKSUM_GEN_IP_INLINE\n      int i;\n#endif /* CHECKSUM_GEN_IP_INLINE */\n      /* round up to a multiple of 4 */\n      optlen_aligned = ((optlen + 3) & ~3);\n      ip_hlen += optlen_aligned;\n      /* First write in the IP options */\n      if (pbuf_header(p, optlen_aligned)) {\n        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"ip_output_if_opt: not enough room for IP options in pbuf\\n\"));\n        IP_STATS_INC(ip.err);\n        snmp_inc_ipoutdiscards();\n        return ERR_BUF;\n      }\n      MEMCPY(p->payload, ip_options, optlen);\n      if (optlen < optlen_aligned) {\n        /* zero the remaining bytes */\n        os_memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);\n      }\n#if CHECKSUM_GEN_IP_INLINE\n      for (i = 0; i < optlen_aligned/2; i++) {\n        chk_sum += ((u16_t*)p->payload)[i];\n      }\n#endif /* CHECKSUM_GEN_IP_INLINE */\n    }\n#endif /* IP_OPTIONS_SEND */\n    /* generate IP header */\n    if (pbuf_header(p, IP_HLEN)) {\n      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"ip_output: not enough room for IP header in pbuf\\n\"));\n\n      IP_STATS_INC(ip.err);\n      snmp_inc_ipoutdiscards();\n      return ERR_BUF;\n    }\n\n    iphdr = (struct ip_hdr *)p->payload;\n    LWIP_ASSERT(\"check that first pbuf can hold struct ip_hdr\",\n               (p->len >= sizeof(struct ip_hdr)));\n\n    IPH_TTL_SET(iphdr, ttl);\n    IPH_PROTO_SET(iphdr, proto);\n#if CHECKSUM_GEN_IP_INLINE\n    chk_sum += LWIP_MAKE_U16(proto, ttl);\n#endif /* CHECKSUM_GEN_IP_INLINE */\n\n    /* dest cannot be NULL here */\n    ip_addr_copy(iphdr->dest, *dest);\n#if CHECKSUM_GEN_IP_INLINE\n    chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;\n    chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;\n#endif /* CHECKSUM_GEN_IP_INLINE */\n\n    IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);\n#if CHECKSUM_GEN_IP_INLINE\n    chk_sum += iphdr->_v_hl_tos;\n#endif /* CHECKSUM_GEN_IP_INLINE */\n    IPH_LEN_SET(iphdr, htons(p->tot_len));\n#if CHECKSUM_GEN_IP_INLINE\n    chk_sum += iphdr->_len;\n#endif /* CHECKSUM_GEN_IP_INLINE */\n    IPH_OFFSET_SET(iphdr, 0);\n    IPH_ID_SET(iphdr, htons(ip_id));\n#if CHECKSUM_GEN_IP_INLINE\n    chk_sum += iphdr->_id;\n#endif /* CHECKSUM_GEN_IP_INLINE */\n    ++ip_id;\n\n    if (ip_addr_isany(src)) {\n      ip_addr_copy(iphdr->src, netif->ip_addr);\n    } else {\n      /* src cannot be NULL here */\n      ip_addr_copy(iphdr->src, *src);\n    }\n\n#if CHECKSUM_GEN_IP_INLINE\n    chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;\n    chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;\n    chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);\n    chk_sum = (chk_sum >> 16) + chk_sum;\n    chk_sum = ~chk_sum;\n    iphdr->_chksum = chk_sum; /* network order */\n#else /* CHECKSUM_GEN_IP_INLINE */\n    IPH_CHKSUM_SET(iphdr, 0);\n#if CHECKSUM_GEN_IP\n    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));\n#endif\n#endif /* CHECKSUM_GEN_IP_INLINE */\n  } else {\n    /* IP header already included in p */\n    iphdr = (struct ip_hdr *)p->payload;\n    ip_addr_copy(dest_addr, iphdr->dest);\n    dest = &dest_addr;\n  }\n\n  IP_STATS_INC(ip.xmit);\n\n  LWIP_DEBUGF(IP_DEBUG, (\"ip_output_if: %c%c%\"U16_F\"\\n\", netif->name[0], netif->name[1], netif->num));\n  ip_debug_print(p);\n\n#if ENABLE_LOOPBACK\n  if (ip_addr_cmp(dest, &netif->ip_addr)) {\n    /* Packet to self, enqueue it for loopback */\n    LWIP_DEBUGF(IP_DEBUG, (\"netif_loop_output()\"));\n    return netif_loop_output(netif, p, dest);\n  }\n#if LWIP_IGMP\n  if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {\n    netif_loop_output(netif, p, dest);\n  }\n#endif /* LWIP_IGMP */\n#endif /* ENABLE_LOOPBACK */\n#if IP_FRAG\n  /* don't fragment if interface has mtu set to 0 [loopif] */\n  if (netif->mtu && (p->tot_len > netif->mtu)) {\n    return ip_frag(p, netif, dest);\n  }\n#endif /* IP_FRAG */\n\n  LWIP_DEBUGF(IP_DEBUG, (\"netif->output()\\n\"));\n  return netif->output(netif, p, dest);\n}\n\n/**\n * Simple interface to ip_output_if. It finds the outgoing network\n * interface and calls upon ip_output_if to do the actual work.\n *\n * @param p the packet to send (p->payload points to the data, e.g. next\n            protocol header; if dest == IP_HDRINCL, p already includes an IP\n            header and p->payload points to that IP header)\n * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\n *         IP  address of the netif used to send is used as source address)\n * @param dest the destination IP address to send the packet to\n * @param ttl the TTL value to be set in the IP header\n * @param tos the TOS value to be set in the IP header\n * @param proto the PROTOCOL to be set in the IP header\n *\n * @return ERR_RTE if no route is found\n *         see ip_output_if() for more return values\n */\nerr_t\nip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,\n          u8_t ttl, u8_t tos, u8_t proto)\n{\n  struct netif *netif;\n\n  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer\n     gets altered as the packet is passed down the stack */\n  LWIP_ASSERT(\"p->ref == 1\", p->ref == 1);\n\n  if ((netif = ip_route(dest)) == NULL) {\n    LWIP_DEBUGF(IP_DEBUG, (\"ip_output: No route to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));\n    IP_STATS_INC(ip.rterr);\n    return ERR_RTE;\n  }\n\n  return ip_output_if(p, src, dest, ttl, tos, proto, netif);\n}\n\n#if LWIP_NETIF_HWADDRHINT\n/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint\n *  before calling ip_output_if.\n *\n * @param p the packet to send (p->payload points to the data, e.g. next\n            protocol header; if dest == IP_HDRINCL, p already includes an IP\n            header and p->payload points to that IP header)\n * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\n *         IP  address of the netif used to send is used as source address)\n * @param dest the destination IP address to send the packet to\n * @param ttl the TTL value to be set in the IP header\n * @param tos the TOS value to be set in the IP header\n * @param proto the PROTOCOL to be set in the IP header\n * @param addr_hint address hint pointer set to netif->addr_hint before\n *        calling ip_output_if()\n *\n * @return ERR_RTE if no route is found\n *         see ip_output_if() for more return values\n */\nerr_t\nip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,\n          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)\n{\n  struct netif *netif;\n  err_t err;\n\n  /* pbufs passed to IP must have a ref-count of 1 as their payload pointer\n     gets altered as the packet is passed down the stack */\n  LWIP_ASSERT(\"p->ref == 1\", p->ref == 1);\n\n  if ((netif = ip_route(dest)) == NULL) {\n    LWIP_DEBUGF(IP_DEBUG, (\"ip_output: No route to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n      ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));\n    IP_STATS_INC(ip.rterr);\n    return ERR_RTE;\n  }\n\n  netif->addr_hint = addr_hint;\n  err = ip_output_if(p, src, dest, ttl, tos, proto, netif);\n  netif->addr_hint = NULL;\n\n  return err;\n}\n#endif /* LWIP_NETIF_HWADDRHINT*/\n\n#if IP_DEBUG\n/* Print an IP header by using LWIP_DEBUGF\n * @param p an IP packet, p->payload pointing to the IP header\n */\nvoid\nip_debug_print(struct pbuf *p)\n{\n  struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;\n  u8_t *payload;\n\n  payload = (u8_t *)iphdr + IP_HLEN;\n\n  LWIP_DEBUGF(IP_DEBUG, (\"IP header:\\n\"));\n  LWIP_DEBUGF(IP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(IP_DEBUG, (\"|%2\"S16_F\" |%2\"S16_F\" |  0x%02\"X16_F\" |     %5\"U16_F\"     | (v, hl, tos, len)\\n\",\n                    IPH_V(iphdr),\n                    IPH_HL(iphdr),\n                    IPH_TOS(iphdr),\n                    ntohs(IPH_LEN(iphdr))));\n  LWIP_DEBUGF(IP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(IP_DEBUG, (\"|    %5\"U16_F\"      |%\"U16_F\"%\"U16_F\"%\"U16_F\"|    %4\"U16_F\"   | (id, flags, offset)\\n\",\n                    ntohs(IPH_ID(iphdr)),\n                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,\n                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,\n                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,\n                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));\n  LWIP_DEBUGF(IP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(IP_DEBUG, (\"|  %3\"U16_F\"  |  %3\"U16_F\"  |    0x%04\"X16_F\"     | (ttl, proto, chksum)\\n\",\n                    IPH_TTL(iphdr),\n                    IPH_PROTO(iphdr),\n                    ntohs(IPH_CHKSUM(iphdr))));\n  LWIP_DEBUGF(IP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(IP_DEBUG, (\"|  %3\"U16_F\"  |  %3\"U16_F\"  |  %3\"U16_F\"  |  %3\"U16_F\"  | (src)\\n\",\n                    ip4_addr1_16(&iphdr->src),\n                    ip4_addr2_16(&iphdr->src),\n                    ip4_addr3_16(&iphdr->src),\n                    ip4_addr4_16(&iphdr->src)));\n  LWIP_DEBUGF(IP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(IP_DEBUG, (\"|  %3\"U16_F\"  |  %3\"U16_F\"  |  %3\"U16_F\"  |  %3\"U16_F\"  | (dest)\\n\",\n                    ip4_addr1_16(&iphdr->dest),\n                    ip4_addr2_16(&iphdr->dest),\n                    ip4_addr3_16(&iphdr->dest),\n                    ip4_addr4_16(&iphdr->dest)));\n  LWIP_DEBUGF(IP_DEBUG, (\"+-------------------------------+\\n\"));\n}\n#endif /* IP_DEBUG */\n"
  },
  {
    "path": "app/lwip/core/ipv4/ip_addr.c",
    "content": "/**\n * @file\n * This is the IPv4 address tools implementation.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n\n/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */\nconst ip_addr_t ip_addr_any ICACHE_RODATA_ATTR = { IPADDR_ANY };\nconst ip_addr_t ip_addr_broadcast ICACHE_RODATA_ATTR = { IPADDR_BROADCAST };\n\n/**\n * Determine if an address is a broadcast address on a network interface \n * \n * @param addr address to be checked\n * @param netif the network interface against which the address is checked\n * @return returns non-zero if the address is a broadcast address\n */\nu8_t\nip4_addr_isbroadcast(u32_t addr, const struct netif *netif)\n{\n  ip_addr_t ipaddr;\n  ip4_addr_set_u32(&ipaddr, addr);\n\n  /* all ones (broadcast) or all zeroes (old skool broadcast) */\n  if ((~addr == IPADDR_ANY) ||\n      (addr == IPADDR_ANY)) {\n    return 1;\n  /* no broadcast support on this network interface? */\n  } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {\n    /* the given address cannot be a broadcast address\n     * nor can we check against any broadcast addresses */\n    return 0;\n  /* address matches network interface address exactly? => no broadcast */\n  } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {\n    return 0;\n  /*  on the same (sub) network... */\n  } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))\n         /* ...and host identifier bits are all ones? =>... */\n          && ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==\n           (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {\n    /* => network broadcast address */\n    return 1;\n  } else {\n    return 0;\n  }\n}\n\n/** Checks if a netmask is valid (starting with ones, then only zeros)\n *\n * @param netmask the IPv4 netmask to check (in network byte order!)\n * @return 1 if the netmask is valid, 0 if it is not\n */\nu8_t\nip4_addr_netmask_valid(u32_t netmask)\n{\n  u32_t mask;\n  u32_t nm_hostorder = lwip_htonl(netmask);\n\n  /* first, check for the first zero */\n  for (mask = 1U << 31 ; mask != 0; mask >>= 1) {\n    if ((nm_hostorder & mask) == 0) {\n      break;\n    }\n  }\n  /* then check that there is no one */\n  for (; mask != 0; mask >>= 1) {\n    if ((nm_hostorder & mask) != 0) {\n      /* there is a one after the first zero -> invalid */\n      return 0;\n    }\n  }\n  /* no one after the first zero -> valid */\n  return 1;\n}\n\n/* Here for now until needed in other places in lwIP */\n#ifndef isprint\n#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)\n#define isprint(c)           in_range(c, 0x20, 0x7f)\n//#define isdigit(c)           in_range(c, '0', '9')\n//#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))\n#define islower(c)           in_range(c, 'a', 'z')\n#define isspace(c)           (c == ' ' || c == '\\f' || c == '\\n' || c == '\\r' || c == '\\t' || c == '\\v')\n#endif\n\n/**\n * Ascii internet address interpretation routine.\n * The value returned is in network order.\n *\n * @param cp IP address in ascii represenation (e.g. \"127.0.0.1\")\n * @return ip address in network order\n */\nu32_t\nipaddr_addr(const char *cp)\n{\n  ip_addr_t val;\n\n  if (ipaddr_aton(cp, &val)) {\n    return ip4_addr_get_u32(&val);\n  }\n  return (IPADDR_NONE);\n}\n\n/**\n * Check whether \"cp\" is a valid ascii representation\n * of an Internet address and convert to a binary address.\n * Returns 1 if the address is valid, 0 if not.\n * This replaces inet_addr, the return value from which\n * cannot distinguish between failure and a local broadcast address.\n *\n * @param cp IP address in ascii represenation (e.g. \"127.0.0.1\")\n * @param addr pointer to which to save the ip address in network order\n * @return 1 if cp could be converted to addr, 0 on failure\n */\nint\nipaddr_aton(const char *cp, ip_addr_t *addr)\n{\n  u32_t val;\n  u8_t base;\n  char c;\n  char ch;\n  unsigned long cutoff;\n  int cutlim;\n  u32_t parts[4];\n  u32_t *pp = parts;\n\n  c = *cp;\n  for (;;) {\n    /*\n     * Collect number up to ``.''.\n     * Values are specified as for C:\n     * 0x=hex, 0=octal, 1-9=decimal.\n     */\n    if (!isdigit(c))\n      return (0);\n    val = 0;\n    base = 10;\n    if (c == '0') {\n      c = *++cp;\n      if (c == 'x' || c == 'X') {\n        base = 16;\n        c = *++cp;\n      } else\n        base = 8;\n    }\n\n    cutoff =(unsigned long)0xffffffff / (unsigned long)base;\n    cutlim =(unsigned long)0xffffffff % (unsigned long)base;\n\n    for (;;) {\n      if (isdigit(c)) {\n    \tch = (int)(c - '0');\n\n    \tif (val > cutoff || (val == cutoff && ch > cutlim))\n    \t\treturn (0);\n\n        val = (val * base) + (int)(c - '0');\n        c = *++cp;\n      } else if (base == 16 && isxdigit(c)) {\n    \tch = (int)(c + 10 - (islower(c) ? 'a' : 'A'));\n\n    \tif (val > cutoff || (val == cutoff && ch > cutlim))\n    \t\treturn (0);\n\n    \tval = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));\n        c = *++cp;\n      } else\n        break;\n    }\n    if (c == '.') {\n      /*\n       * Internet format:\n       *  a.b.c.d\n       *  a.b.c   (with c treated as 16 bits)\n       *  a.b (with b treated as 24 bits)\n       */\n      if (pp >= parts + 3) {\n        return (0);\n      }\n      *pp++ = val;\n      c = *++cp;\n    } else\n      break;\n  }\n  /*\n   * Check for trailing characters.\n   */\n  if (c != '\\0' && !isspace(c)) {\n    return (0);\n  }\n  /*\n   * Concoct the address according to\n   * the number of parts specified.\n   */\n  switch (pp - parts + 1) {\n\n  case 0:\n    return (0);       /* initial nondigit */\n\n  case 1:             /* a -- 32 bits */\n    break;\n\n  case 2:             /* a.b -- 8.24 bits */\n    if ((val > 0xffffffUL) || (parts[0] > 0xff)) {\n      return (0);\n    }\n    val |= parts[0] << 24;\n    break;\n\n  case 3:             /* a.b.c -- 8.8.16 bits */\n    if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) {\n      return (0);\n    }\n    val |= (parts[0] << 24) | (parts[1] << 16);\n    break;\n\n  case 4:             /* a.b.c.d -- 8.8.8.8 bits */\n    if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) {\n      return (0);\n    }\n    val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);\n    break;\n  default:\n    LWIP_ASSERT(\"unhandled\", 0);\n    break;\n  }\n  if (addr) {\n    ip4_addr_set_u32(addr, htonl(val));\n  }\n  return (1);\n}\n\n/**\n * Convert numeric IP address into decimal dotted ASCII representation.\n * returns ptr to static buffer; not reentrant!\n *\n * @param addr ip address in network order to convert\n * @return pointer to a global static (!) buffer that holds the ASCII\n *         represenation of addr\n */\nchar *\nipaddr_ntoa(const ip_addr_t *addr)\n{\n  static char str[16];\n  return ipaddr_ntoa_r(addr, str, 16);\n}\n\n/**\n * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.\n *\n * @param addr ip address in network order to convert\n * @param buf target buffer where the string is stored\n * @param buflen length of buf\n * @return either pointer to buf which now holds the ASCII\n *         representation of addr or NULL if buf was too small\n */\nchar *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen)\n{\n  u32_t s_addr;\n  char inv[3];\n  char *rp;\n  u8_t *ap;\n  u8_t rem;\n  u8_t n;\n  u8_t i;\n  int len = 0;\n\n  s_addr = ip4_addr_get_u32(addr);\n\n  rp = buf;\n  ap = (u8_t *)&s_addr;\n  for(n = 0; n < 4; n++) {\n    i = 0;\n    do {\n      rem = *ap % (u8_t)10;\n      *ap /= (u8_t)10;\n      inv[i++] = '0' + rem;\n    } while(*ap);\n    while(i--) {\n      if (len++ >= buflen) {\n        return NULL;\n      }\n      *rp++ = inv[i];\n    }\n    if (len++ >= buflen) {\n      return NULL;\n    }\n    *rp++ = '.';\n    ap++;\n  }\n  *--rp = 0;\n  return buf;\n}\n"
  },
  {
    "path": "app/lwip/core/ipv4/ip_frag.c",
    "content": "/**\n * @file\n * This is the IPv4 packet segmentation and reassembly implementation.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Jani Monoses <jani@iv.ro> \n *         Simon Goldschmidt\n * original reassembly code by Adam Dunkels <adam@sics.se>\n * \n */\n\n#include \"lwip/opt.h\"\n#include \"lwip/ip_frag.h\"\n#include \"lwip/def.h\"\n#include \"lwip/inet_chksum.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/snmp.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/icmp.h\"\n\n#include <string.h>\n\n#if IP_REASSEMBLY\n/**\n * The IP reassembly code currently has the following limitations:\n * - IP header options are not supported\n * - fragments must not overlap (e.g. due to different routes),\n *   currently, overlapping or duplicate fragments are thrown away\n *   if IP_REASS_CHECK_OVERLAP=1 (the default)!\n *\n * @todo: work with IP header options\n */\n\n/** Setting this to 0, you can turn off checking the fragments for overlapping\n * regions. The code gets a little smaller. Only use this if you know that\n * overlapping won't occur on your network! */\n#ifndef IP_REASS_CHECK_OVERLAP\n#define IP_REASS_CHECK_OVERLAP 1\n#endif /* IP_REASS_CHECK_OVERLAP */\n\n/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is\n * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.\n * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA\n * is set to 1, so one datagram can be reassembled at a time, only. */\n#ifndef IP_REASS_FREE_OLDEST\n#define IP_REASS_FREE_OLDEST 1\n#endif /* IP_REASS_FREE_OLDEST */\n\n#define IP_REASS_FLAG_LASTFRAG 0x01\n\n/** This is a helper struct which holds the starting\n * offset and the ending offset of this fragment to\n * easily chain the fragments.\n * It has the same packing requirements as the IP header, since it replaces\n * the IP header in memory in incoming fragments (after copying it) to keep\n * track of the various fragments. (-> If the IP header doesn't need packing,\n * this struct doesn't need packing, too.)\n */\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\nstruct ip_reass_helper {\n  PACK_STRUCT_FIELD(struct pbuf *next_pbuf);\n  PACK_STRUCT_FIELD(u16_t start);\n  PACK_STRUCT_FIELD(u16_t end);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB)  \\\n  (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \\\n   ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \\\n   IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0\n\n/* global variables */\nstatic struct ip_reassdata *reassdatagrams;\nstatic u16_t ip_reass_pbufcount;\n\n/* function prototypes */\nstatic void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)ICACHE_FLASH_ATTR;\nstatic int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)ICACHE_FLASH_ATTR;\n\n/**\n * Reassembly timer base function\n * for both NO_SYS == 0 and 1 (!).\n *\n * Should be called every 1000 msec (defined by IP_TMR_INTERVAL).\n */\nvoid\nip_reass_tmr(void)\n{\n  struct ip_reassdata *r, *prev = NULL;\n\n  r = reassdatagrams;\n  while (r != NULL) {\n    /* Decrement the timer. Once it reaches 0,\n     * clean up the incomplete fragment assembly */\n    if (r->timer > 0) {\n      r->timer--;\n      LWIP_DEBUGF(IP_REASS_DEBUG, (\"ip_reass_tmr: timer dec %\"U16_F\"\\n\",(u16_t)r->timer));\n      prev = r;\n      r = r->next;\n    } else {\n      /* reassembly timed out */\n      struct ip_reassdata *tmp;\n      LWIP_DEBUGF(IP_REASS_DEBUG, (\"ip_reass_tmr: timer timed out\\n\"));\n      tmp = r;\n      /* get the next pointer before freeing */\n      r = r->next;\n      /* free the helper struct and all enqueued pbufs */\n      ip_reass_free_complete_datagram(tmp, prev);\n     }\n   }\n}\n\n/**\n * Free a datagram (struct ip_reassdata) and all its pbufs.\n * Updates the total count of enqueued pbufs (ip_reass_pbufcount),\n * SNMP counters and sends an ICMP time exceeded packet.\n *\n * @param ipr datagram to free\n * @param prev the previous datagram in the linked list\n * @return the number of pbufs freed\n */\nstatic int\nip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)\n{\n  u16_t pbufs_freed = 0;\n  u8_t clen;\n  struct pbuf *p;\n  struct ip_reass_helper *iprh;\n\n  LWIP_ASSERT(\"prev != ipr\", prev != ipr);\n  if (prev != NULL) {\n    LWIP_ASSERT(\"prev->next == ipr\", prev->next == ipr);\n  }\n\n  snmp_inc_ipreasmfails();\n#if LWIP_ICMP\n  iprh = (struct ip_reass_helper *)ipr->p->payload;\n  if (iprh->start == 0) {\n    /* The first fragment was received, send ICMP time exceeded. */\n    /* First, de-queue the first pbuf from r->p. */\n    p = ipr->p;\n    ipr->p = iprh->next_pbuf;\n    /* Then, copy the original header into it. */\n    SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);\n    icmp_time_exceeded(p, ICMP_TE_FRAG);\n    clen = pbuf_clen(p);\n    LWIP_ASSERT(\"pbufs_freed + clen <= 0xffff\", pbufs_freed + clen <= 0xffff);\n    pbufs_freed += clen;\n    pbuf_free(p);\n  }\n#endif /* LWIP_ICMP */\n\n  /* First, free all received pbufs.  The individual pbufs need to be released \n     separately as they have not yet been chained */\n  p = ipr->p;\n  while (p != NULL) {\n    struct pbuf *pcur;\n    iprh = (struct ip_reass_helper *)p->payload;\n    pcur = p;\n    /* get the next pointer before freeing */\n    p = iprh->next_pbuf;\n    clen = pbuf_clen(pcur);\n    LWIP_ASSERT(\"pbufs_freed + clen <= 0xffff\", pbufs_freed + clen <= 0xffff);\n    pbufs_freed += clen;\n    pbuf_free(pcur);\n  }\n  /* Then, unchain the struct ip_reassdata from the list and free it. */\n  ip_reass_dequeue_datagram(ipr, prev);\n  LWIP_ASSERT(\"ip_reass_pbufcount >= clen\", ip_reass_pbufcount >= pbufs_freed);\n  ip_reass_pbufcount -= pbufs_freed;\n\n  return pbufs_freed;\n}\n\n#if IP_REASS_FREE_OLDEST\n/**\n * Free the oldest datagram to make room for enqueueing new fragments.\n * The datagram 'fraghdr' belongs to is not freed!\n *\n * @param fraghdr IP header of the current fragment\n * @param pbufs_needed number of pbufs needed to enqueue\n *        (used for freeing other datagrams if not enough space)\n * @return the number of pbufs freed\n */\nstatic int\nip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)\n{\n  /* @todo Can't we simply remove the last datagram in the\n   *       linked list behind reassdatagrams?\n   */\n  struct ip_reassdata *r, *oldest, *prev;\n  int pbufs_freed = 0, pbufs_freed_current;\n  int other_datagrams;\n\n  /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,\n   * but don't free the datagram that 'fraghdr' belongs to! */\n  do {\n    oldest = NULL;\n    prev = NULL;\n    other_datagrams = 0;\n    r = reassdatagrams;\n    while (r != NULL) {\n      if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {\n        /* Not the same datagram as fraghdr */\n        other_datagrams++;\n        if (oldest == NULL) {\n          oldest = r;\n        } else if (r->timer <= oldest->timer) {\n          /* older than the previous oldest */\n          oldest = r;\n        }\n      }\n      if (r->next != NULL) {\n        prev = r;\n      }\n      r = r->next;\n    }\n    if (oldest != NULL) {\n      pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);\n      pbufs_freed += pbufs_freed_current;\n    }\n  } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));\n  return pbufs_freed;\n}\n#endif /* IP_REASS_FREE_OLDEST */\n\n/**\n * Enqueues a new fragment into the fragment queue\n * @param fraghdr points to the new fragments IP hdr\n * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)\n * @return A pointer to the queue location into which the fragment was enqueued\n */\nstatic struct ip_reassdata* ICACHE_FLASH_ATTR\nip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)\n{\n  struct ip_reassdata* ipr;\n  /* No matching previous fragment found, allocate a new reassdata struct */\n  ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);\n  if (ipr == NULL) {\n#if IP_REASS_FREE_OLDEST\n    if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {\n      ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA);\n    }\n    if (ipr == NULL)\n#endif /* IP_REASS_FREE_OLDEST */\n    {\n      IPFRAG_STATS_INC(ip_frag.memerr);\n      LWIP_DEBUGF(IP_REASS_DEBUG,(\"Failed to alloc reassdata struct\\n\"));\n      return NULL;\n    }\n  }\n  os_memset(ipr, 0, sizeof(struct ip_reassdata));\n  ipr->timer = IP_REASS_MAXAGE;\n\n  /* enqueue the new structure to the front of the list */\n  ipr->next = reassdatagrams;\n  reassdatagrams = ipr;\n  /* copy the ip header for later tests and input */\n  /* @todo: no ip options supported? */\n  SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);\n  return ipr;\n}\n\n/**\n * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.\n * @param ipr points to the queue entry to dequeue\n */\nstatic void ICACHE_FLASH_ATTR\nip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)\n{\n  \n  /* dequeue the reass struct  */\n  if (reassdatagrams == ipr) {\n    /* it was the first in the list */\n    reassdatagrams = ipr->next;\n  } else {\n    /* it wasn't the first, so it must have a valid 'prev' */\n    LWIP_ASSERT(\"sanity check linked list\", prev != NULL);\n    prev->next = ipr->next;\n  }\n\n  /* now we can free the ip_reass struct */\n  memp_free(MEMP_REASSDATA, ipr);\n}\n\n/**\n * Chain a new pbuf into the pbuf list that composes the datagram.  The pbuf list\n * will grow over time as  new pbufs are rx.\n * Also checks that the datagram passes basic continuity checks (if the last\n * fragment was received at least once).\n * @param root_p points to the 'root' pbuf for the current datagram being assembled.\n * @param new_p points to the pbuf for the current fragment\n * @return 0 if invalid, >0 otherwise\n */\nstatic int ICACHE_FLASH_ATTR\nip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)\n{\n  struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;\n  struct pbuf *q;\n  u16_t offset,len;\n  struct ip_hdr *fraghdr;\n  int valid = 1;\n\n  /* Extract length and fragment offset from current fragment */\n  fraghdr = (struct ip_hdr*)new_p->payload; \n  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;\n  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;\n\n  /* overwrite the fragment's ip header from the pbuf with our helper struct,\n   * and setup the embedded helper structure. */\n  /* make sure the struct ip_reass_helper fits into the IP header */\n  LWIP_ASSERT(\"sizeof(struct ip_reass_helper) <= IP_HLEN\",\n              sizeof(struct ip_reass_helper) <= IP_HLEN);\n  iprh = (struct ip_reass_helper*)new_p->payload;\n  iprh->next_pbuf = NULL;\n  iprh->start = offset;\n  iprh->end = offset + len;\n\n  /* Iterate through until we either get to the end of the list (append),\n   * or we find on with a larger offset (insert). */\n  for (q = ipr->p; q != NULL;) {\n    iprh_tmp = (struct ip_reass_helper*)q->payload;\n    if (iprh->start < iprh_tmp->start) {\n      /* the new pbuf should be inserted before this */\n      iprh->next_pbuf = q;\n      if (iprh_prev != NULL) {\n        /* not the fragment with the lowest offset */\n#if IP_REASS_CHECK_OVERLAP\n        if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {\n          /* fragment overlaps with previous or following, throw away */\n          goto freepbuf;\n        }\n#endif /* IP_REASS_CHECK_OVERLAP */\n        iprh_prev->next_pbuf = new_p;\n      } else {\n        /* fragment with the lowest offset */\n        ipr->p = new_p;\n      }\n      break;\n    } else if(iprh->start == iprh_tmp->start) {\n      /* received the same datagram twice: no need to keep the datagram */\n      goto freepbuf;\n#if IP_REASS_CHECK_OVERLAP\n    } else if(iprh->start < iprh_tmp->end) {\n      /* overlap: no need to keep the new datagram */\n      goto freepbuf;\n#endif /* IP_REASS_CHECK_OVERLAP */\n    } else {\n      /* Check if the fragments received so far have no wholes. */\n      if (iprh_prev != NULL) {\n        if (iprh_prev->end != iprh_tmp->start) {\n          /* There is a fragment missing between the current\n           * and the previous fragment */\n          valid = 0;\n        }\n      }\n    }\n    q = iprh_tmp->next_pbuf;\n    iprh_prev = iprh_tmp;\n  }\n\n  /* If q is NULL, then we made it to the end of the list. Determine what to do now */\n  if (q == NULL) {\n    if (iprh_prev != NULL) {\n      /* this is (for now), the fragment with the highest offset:\n       * chain it to the last fragment */\n#if IP_REASS_CHECK_OVERLAP\n      LWIP_ASSERT(\"check fragments don't overlap\", iprh_prev->end <= iprh->start);\n#endif /* IP_REASS_CHECK_OVERLAP */\n      iprh_prev->next_pbuf = new_p;\n      if (iprh_prev->end != iprh->start) {\n        valid = 0;\n      }\n    } else {\n#if IP_REASS_CHECK_OVERLAP\n      LWIP_ASSERT(\"no previous fragment, this must be the first fragment!\",\n        ipr->p == NULL);\n#endif /* IP_REASS_CHECK_OVERLAP */\n      /* this is the first fragment we ever received for this ip datagram */\n      ipr->p = new_p;\n    }\n  }\n\n  /* At this point, the validation part begins: */\n  /* If we already received the last fragment */\n  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {\n    /* and had no wholes so far */\n    if (valid) {\n      /* then check if the rest of the fragments is here */\n      /* Check if the queue starts with the first datagram */\n      if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {\n        valid = 0;\n      } else {\n        /* and check that there are no wholes after this datagram */\n        iprh_prev = iprh;\n        q = iprh->next_pbuf;\n        while (q != NULL) {\n          iprh = (struct ip_reass_helper*)q->payload;\n          if (iprh_prev->end != iprh->start) {\n            valid = 0;\n            break;\n          }\n          iprh_prev = iprh;\n          q = iprh->next_pbuf;\n        }\n        /* if still valid, all fragments are received\n         * (because to the MF==0 already arrived */\n        if (valid) {\n          LWIP_ASSERT(\"sanity check\", ipr->p != NULL);\n          LWIP_ASSERT(\"sanity check\",\n            ((struct ip_reass_helper*)ipr->p->payload) != iprh);\n          LWIP_ASSERT(\"validate_datagram:next_pbuf!=NULL\",\n            iprh->next_pbuf == NULL);\n          LWIP_ASSERT(\"validate_datagram:datagram end!=datagram len\",\n            iprh->end == ipr->datagram_len);\n        }\n      }\n    }\n    /* If valid is 0 here, there are some fragments missing in the middle\n     * (since MF == 0 has already arrived). Such datagrams simply time out if\n     * no more fragments are received... */\n    return valid;\n  }\n  /* If we come here, not all fragments were received, yet! */\n  return 0; /* not yet valid! */\n#if IP_REASS_CHECK_OVERLAP\nfreepbuf:\n  ip_reass_pbufcount -= pbuf_clen(new_p);\n  pbuf_free(new_p);\n  return 0;\n#endif /* IP_REASS_CHECK_OVERLAP */\n}\n\n/**\n * Reassembles incoming IP fragments into an IP datagram.\n *\n * @param p points to a pbuf chain of the fragment\n * @return NULL if reassembly is incomplete, ? otherwise\n */\nstruct pbuf *\nip_reass(struct pbuf *p)\n{\n  struct pbuf *r;\n  struct ip_hdr *fraghdr;\n  struct ip_reassdata *ipr;\n  struct ip_reass_helper *iprh;\n  u16_t offset, len;\n  u8_t clen;\n  struct ip_reassdata *ipr_prev = NULL;\n\n  IPFRAG_STATS_INC(ip_frag.recv);\n  snmp_inc_ipreasmreqds();\n\n  fraghdr = (struct ip_hdr*)p->payload;\n\n  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {\n    LWIP_DEBUGF(IP_REASS_DEBUG,(\"ip_reass: IP options currently not supported!\\n\"));\n    IPFRAG_STATS_INC(ip_frag.err);\n    goto nullreturn;\n  }\n\n  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;\n  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;\n\n  /* Check if we are allowed to enqueue more datagrams. */\n  clen = pbuf_clen(p);\n  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {\n#if IP_REASS_FREE_OLDEST\n    if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||\n        ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))\n#endif /* IP_REASS_FREE_OLDEST */\n    {\n      /* No datagram could be freed and still too many pbufs enqueued */\n      LWIP_DEBUGF(IP_REASS_DEBUG,(\"ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\\n\",\n        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));\n      IPFRAG_STATS_INC(ip_frag.memerr);\n      /* @todo: send ICMP time exceeded here? */\n      /* drop this pbuf */\n      goto nullreturn;\n    }\n  }\n\n  /* Look for the datagram the fragment belongs to in the current datagram queue,\n   * remembering the previous in the queue for later dequeueing. */\n  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {\n    /* Check if the incoming fragment matches the one currently present\n       in the reassembly buffer. If so, we proceed with copying the\n       fragment into the buffer. */\n    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {\n      LWIP_DEBUGF(IP_REASS_DEBUG, (\"ip_reass: matching previous fragment ID=%\"X16_F\"\\n\",\n        ntohs(IPH_ID(fraghdr))));\n      IPFRAG_STATS_INC(ip_frag.cachehit);\n      break;\n    }\n    ipr_prev = ipr;\n  }\n\n  if (ipr == NULL) {\n  /* Enqueue a new datagram into the datagram queue */\n    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);\n    /* Bail if unable to enqueue */\n    if(ipr == NULL) {\n      goto nullreturn;\n    }\n  } else {\n    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && \n      ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {\n      /* ipr->iphdr is not the header from the first fragment, but fraghdr is\n       * -> copy fraghdr into ipr->iphdr since we want to have the header\n       * of the first fragment (for ICMP time exceeded and later, for copying\n       * all options, if supported)*/\n      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);\n    }\n  }\n  /* Track the current number of pbufs current 'in-flight', in order to limit \n  the number of fragments that may be enqueued at any one time */\n  ip_reass_pbufcount += clen;\n\n  /* At this point, we have either created a new entry or pointing \n   * to an existing one */\n\n  /* check for 'no more fragments', and update queue entry*/\n  if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {\n    ipr->flags |= IP_REASS_FLAG_LASTFRAG;\n    ipr->datagram_len = offset + len;\n    LWIP_DEBUGF(IP_REASS_DEBUG,\n     (\"ip_reass: last fragment seen, total len %\"S16_F\"\\n\",\n      ipr->datagram_len));\n  }\n  /* find the right place to insert this pbuf */\n  /* @todo: trim pbufs if fragments are overlapping */\n  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {\n    /* the totally last fragment (flag more fragments = 0) was received at least\n     * once AND all fragments are received */\n    ipr->datagram_len += IP_HLEN;\n\n    /* save the second pbuf before copying the header over the pointer */\n    r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;\n\n    /* copy the original ip header back to the first pbuf */\n    fraghdr = (struct ip_hdr*)(ipr->p->payload);\n    SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);\n    IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));\n    IPH_OFFSET_SET(fraghdr, 0);\n    IPH_CHKSUM_SET(fraghdr, 0);\n    /* @todo: do we need to set calculate the correct checksum? */\n    IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));\n\n    p = ipr->p;\n\n    /* chain together the pbufs contained within the reass_data list. */\n    while(r != NULL) {\n      iprh = (struct ip_reass_helper*)r->payload;\n\n      /* hide the ip header for every succeding fragment */\n      pbuf_header(r, -IP_HLEN);\n      pbuf_cat(p, r);\n      r = iprh->next_pbuf;\n    }\n    /* release the sources allocate for the fragment queue entry */\n    ip_reass_dequeue_datagram(ipr, ipr_prev);\n\n    /* and adjust the number of pbufs currently queued for reassembly. */\n    ip_reass_pbufcount -= pbuf_clen(p);\n\n    /* Return the pbuf chain */\n    return p;\n  }\n  /* the datagram is not (yet?) reassembled completely */\n  LWIP_DEBUGF(IP_REASS_DEBUG,(\"ip_reass_pbufcount: %d out\\n\", ip_reass_pbufcount));\n  return NULL;\n\nnullreturn:\n  LWIP_DEBUGF(IP_REASS_DEBUG,(\"ip_reass: nullreturn\\n\"));\n  IPFRAG_STATS_INC(ip_frag.drop);\n  pbuf_free(p);\n  return NULL;\n}\n#endif /* IP_REASSEMBLY */\n\n#if IP_FRAG\n#if IP_FRAG_USES_STATIC_BUF\nstatic u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];\n#else /* IP_FRAG_USES_STATIC_BUF */\n\n#if !LWIP_NETIF_TX_SINGLE_PBUF\n/** Allocate a new struct pbuf_custom_ref */\nstatic struct pbuf_custom_ref* ICACHE_FLASH_ATTR\nip_frag_alloc_pbuf_custom_ref(void)\n{\n  return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);\n}\n\n/** Free a struct pbuf_custom_ref */\nstatic void ICACHE_FLASH_ATTR\nip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)\n{\n  LWIP_ASSERT(\"p != NULL\", p != NULL);\n  memp_free(MEMP_FRAG_PBUF, p);\n}\n\n/** Free-callback function to free a 'struct pbuf_custom_ref', called by\n * pbuf_free. */\nstatic void ICACHE_FLASH_ATTR\nipfrag_free_pbuf_custom(struct pbuf *p)\n{\n  struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p;\n  LWIP_ASSERT(\"pcr != NULL\", pcr != NULL);\n  LWIP_ASSERT(\"pcr == p\", (void*)pcr == (void*)p);\n  if (pcr->original != NULL) {\n    pbuf_free(pcr->original);\n  }\n  ip_frag_free_pbuf_custom_ref(pcr);\n}\n#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */\n#endif /* IP_FRAG_USES_STATIC_BUF */\n\n/**\n * Fragment an IP datagram if too large for the netif.\n *\n * Chop the datagram in MTU sized chunks and send them in order\n * by using a fixed size static memory buffer (PBUF_REF) or\n * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).\n *\n * @param p ip packet to send\n * @param netif the netif on which to send\n * @param dest destination ip address to which to send\n *\n * @return ERR_OK if sent successfully, err_t otherwise\n */\nerr_t \nip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)\n{\n  struct pbuf *rambuf;\n#if IP_FRAG_USES_STATIC_BUF\n  struct pbuf *header;\n#else\n#if !LWIP_NETIF_TX_SINGLE_PBUF\n  struct pbuf *newpbuf;\n#endif\n  struct ip_hdr *original_iphdr;\n#endif\n  struct ip_hdr *iphdr;\n  u16_t nfb;\n  u16_t left, cop;\n  u16_t mtu = netif->mtu;\n  u16_t ofo, omf;\n  u16_t last;\n  u16_t poff = IP_HLEN;\n  u16_t tmp;\n#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF\n  u16_t newpbuflen = 0;\n  u16_t left_to_copy;\n#endif\n\n  /* Get a RAM based MTU sized pbuf */\n#if IP_FRAG_USES_STATIC_BUF\n  /* When using a static buffer, we use a PBUF_REF, which we will\n   * use to reference the packet (without link header).\n   * Layer and length is irrelevant.\n   */\n  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);\n  if (rambuf == NULL) {\n    LWIP_DEBUGF(IP_REASS_DEBUG, (\"ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\\n\"));\n    return ERR_MEM;\n  }\n  rambuf->tot_len = rambuf->len = mtu;\n  rambuf->payload = LWIP_MEM_ALIGN((void *)buf);\n\n  /* Copy the IP header in it */\n  iphdr = (struct ip_hdr *)rambuf->payload;\n  SMEMCPY(iphdr, p->payload, IP_HLEN);\n#else /* IP_FRAG_USES_STATIC_BUF */\n  original_iphdr = (struct ip_hdr *)p->payload;\n  iphdr = original_iphdr;\n#endif /* IP_FRAG_USES_STATIC_BUF */\n\n  /* Save original offset */\n  tmp = ntohs(IPH_OFFSET(iphdr));\n  ofo = tmp & IP_OFFMASK;\n  omf = tmp & IP_MF;\n\n  left = p->tot_len - IP_HLEN;\n\n  nfb = (mtu - IP_HLEN) / 8;\n\n  while (left) {\n    last = (left <= mtu - IP_HLEN);\n\n    /* Set new offset and MF flag */\n    tmp = omf | (IP_OFFMASK & (ofo));\n    if (!last) {\n      tmp = tmp | IP_MF;\n    }\n\n    /* Fill this fragment */\n    cop = last ? left : nfb * 8;\n\n#if IP_FRAG_USES_STATIC_BUF\n    poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);\n#else /* IP_FRAG_USES_STATIC_BUF */\n#if LWIP_NETIF_TX_SINGLE_PBUF\n    rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);\n    if (rambuf == NULL) {\n      return ERR_MEM;\n    }\n    LWIP_ASSERT(\"this needs a pbuf in one piece!\",\n      (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));\n    poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);\n    /* make room for the IP header */\n    if(pbuf_header(rambuf, IP_HLEN)) {\n      pbuf_free(rambuf);\n      return ERR_MEM;\n    }\n    /* fill in the IP header */\n    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);\n    iphdr = rambuf->payload;\n#else /* LWIP_NETIF_TX_SINGLE_PBUF */\n    /* When not using a static buffer, create a chain of pbufs.\n     * The first will be a PBUF_RAM holding the link and IP header.\n     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,\n     * but limited to the size of an mtu.\n     */\n    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);\n    if (rambuf == NULL) {\n      return ERR_MEM;\n    }\n    LWIP_ASSERT(\"this needs a pbuf in one piece!\",\n                (p->len >= (IP_HLEN)));\n    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);\n    iphdr = (struct ip_hdr *)rambuf->payload;\n\n    /* Can just adjust p directly for needed offset. */\n    p->payload = (u8_t *)p->payload + poff;\n    p->len -= poff;\n\n    left_to_copy = cop;\n    while (left_to_copy) {\n      struct pbuf_custom_ref *pcr;\n      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;\n      /* Is this pbuf already empty? */\n      if (!newpbuflen) {\n        p = p->next;\n        continue;\n      }\n      pcr = ip_frag_alloc_pbuf_custom_ref();\n      if (pcr == NULL) {\n        pbuf_free(rambuf);\n        return ERR_MEM;\n      }\n      /* Mirror this pbuf, although we might not need all of it. */\n      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);\n      if (newpbuf == NULL) {\n        ip_frag_free_pbuf_custom_ref(pcr);\n        pbuf_free(rambuf);\n        return ERR_MEM;\n      }\n      pbuf_ref(p);\n      pcr->original = p;\n      pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;\n\n      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain\n       * so that it is removed when pbuf_dechain is later called on rambuf.\n       */\n      pbuf_cat(rambuf, newpbuf);\n      left_to_copy -= newpbuflen;\n      if (left_to_copy) {\n        p = p->next;\n      }\n    }\n    poff = newpbuflen;\n#endif /* LWIP_NETIF_TX_SINGLE_PBUF */\n#endif /* IP_FRAG_USES_STATIC_BUF */\n\n    /* Correct header */\n    IPH_OFFSET_SET(iphdr, htons(tmp));\n    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));\n    IPH_CHKSUM_SET(iphdr, 0);\n    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\n\n#if IP_FRAG_USES_STATIC_BUF\n    if (last) {\n      pbuf_realloc(rambuf, left + IP_HLEN);\n    }\n\n    /* This part is ugly: we alloc a RAM based pbuf for \n     * the link level header for each chunk and then \n     * free it.A PBUF_ROM style pbuf for which pbuf_header\n     * worked would make things simpler.\n     */\n    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);\n    if (header != NULL) {\n      pbuf_chain(header, rambuf);\n      netif->output(netif, header, dest);\n      IPFRAG_STATS_INC(ip_frag.xmit);\n      snmp_inc_ipfragcreates();\n      pbuf_free(header);\n    } else {\n      LWIP_DEBUGF(IP_REASS_DEBUG, (\"ip_frag: pbuf_alloc() for header failed\\n\"));\n      pbuf_free(rambuf);\n      return ERR_MEM;\n    }\n#else /* IP_FRAG_USES_STATIC_BUF */\n    /* No need for separate header pbuf - we allowed room for it in rambuf\n     * when allocated.\n     */\n    netif->output(netif, rambuf, dest);\n    IPFRAG_STATS_INC(ip_frag.xmit);\n\n    /* Unfortunately we can't reuse rambuf - the hardware may still be\n     * using the buffer. Instead we free it (and the ensuing chain) and\n     * recreate it next time round the loop. If we're lucky the hardware\n     * will have already sent the packet, the free will really free, and\n     * there will be zero memory penalty.\n     */\n    \n    pbuf_free(rambuf);\n#endif /* IP_FRAG_USES_STATIC_BUF */\n    left -= cop;\n    ofo += nfb;\n  }\n#if IP_FRAG_USES_STATIC_BUF\n  pbuf_free(rambuf);\n#endif /* IP_FRAG_USES_STATIC_BUF */\n  snmp_inc_ipfragoks();\n  return ERR_OK;\n}\n#endif /* IP_FRAG */\n"
  },
  {
    "path": "app/lwip/core/mdns.c",
    "content": "/**\n * lwip MDNS resolver file.\n *\n * Created on: Jul 29, 2010\n * Author: Daniel Toma\n *\n\n * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote\n *    products derived from this software without specific prior\n *    written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\n * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n\n * This file implements a MDNS host name and PUCK service registration.\n\n *-----------------------------------------------------------------------------\n * Includes\n *----------------------------------------------------------------------------*/\n#include \"lwip/opt.h\"\n#if LWIP_MDNS /* don't build if not configured for use in lwipopts.h */\n#include \"lwip/mdns.h\"\n#include \"lwip/puck_def.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/igmp.h\"\n#include \"osapi.h\"\n#include \"os_type.h\"\n#include \"user_interface.h\"\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/** DNS server IP address */\n#ifndef DNS_MULTICAST_ADDRESS\n#define DNS_MULTICAST_ADDRESS        ipaddr_addr(\"224.0.0.251\") /* resolver1.opendns.com */\n#endif\n\n/** DNS server IP address */\n#ifndef MDNS_LOCAL\n#define MDNS_LOCAL                \"local\" /* resolver1.opendns.com */\n#endif\n\n/** DNS server port address */\n#ifndef DNS_MDNS_PORT\n#define DNS_MDNS_PORT           5353\n#endif\n\n/** DNS maximum number of retries when asking for a name, before \"timeout\". */\n#ifndef DNS_MAX_RETRIES\n#define DNS_MAX_RETRIES           4\n#endif\n\n/** DNS resource record max. TTL (one week as default) */\n#ifndef DNS_MAX_TTL\n#define DNS_MAX_TTL               604800\n#endif\n\n/* DNS protocol flags */\n#define DNS_FLAG1_RESPONSE        0x84\n#define DNS_FLAG1_OPCODE_STATUS   0x10\n#define DNS_FLAG1_OPCODE_INVERSE  0x08\n#define DNS_FLAG1_OPCODE_STANDARD 0x00\n#define DNS_FLAG1_AUTHORATIVE     0x04\n#define DNS_FLAG1_TRUNC           0x02\n#define DNS_FLAG1_RD              0x01\n#define DNS_FLAG2_RA              0x80\n#define DNS_FLAG2_ERR_MASK        0x0f\n#define DNS_FLAG2_ERR_NONE        0x00\n#define DNS_FLAG2_ERR_NAME        0x03\n\n/* DNS protocol states */\n#define DNS_STATE_UNUSED          0\n#define DNS_STATE_NEW             1\n#define DNS_STATE_ASKING          2\n#define DNS_STATE_DONE            3\n\n/* MDNS registration type */\n#define MDNS_HOSTNAME_REG         0\n#define MDNS_SERVICE_REG          1\n\n/* MDNS registration type */\n#define MDNS_REG_ANSWER           1\n#define MDNS_SD_ANSWER            2\n#define MDNS_SERVICE_REG_ANSWER   3\n\n/* MDNS registration time */\n#define MDNS_HOST_TIME            120\n#define MDNS_SERVICE_TIME         3600\n\n/** MDNS name length with \".\" at the beginning and end of name*/\n#ifndef MDNS_LENGTH_ADD\n#define MDNS_LENGTH_ADD           2\n#endif\n\n#ifdef MDNS_MAX_NAME_LENGTH\n#undef MDNS_MAX_NAME_LENGTH\n#endif\n#define MDNS_MAX_NAME_LENGTH      (256)\n\nPACK_STRUCT_BEGIN\n/** DNS message header */\nstruct mdns_hdr {\n\tPACK_STRUCT_FIELD(u16_t id);\n\tPACK_STRUCT_FIELD(u8_t flags1);\n\tPACK_STRUCT_FIELD(u8_t flags2);\n\tPACK_STRUCT_FIELD(u16_t numquestions);\n\tPACK_STRUCT_FIELD(u16_t numanswers);\n\tPACK_STRUCT_FIELD(u16_t numauthrr);\n\tPACK_STRUCT_FIELD(u16_t numextrarr);\n}PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n\n#define SIZEOF_DNS_HDR 12\n\nPACK_STRUCT_BEGIN\n/** MDNS query message structure */\nstruct mdns_query {\n\t/* MDNS query record starts with either a domain name or a pointer\n\t to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type);\n\tPACK_STRUCT_FIELD(u16_t class);\n}PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n\n#define SIZEOF_DNS_QUERY 4\n\nPACK_STRUCT_BEGIN\n/** MDNS answer message structure */\nstruct mdns_answer {\n\t/* MDNS answer record starts with either a domain name or a pointer\n\t to a name already present somewhere in the packet. */PACK_STRUCT_FIELD(u16_t type);\n\tPACK_STRUCT_FIELD(u16_t class);\n\tPACK_STRUCT_FIELD(u32_t ttl);\n\tPACK_STRUCT_FIELD(u16_t len);\n}PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#define SIZEOF_DNS_ANSWER 10\n\nPACK_STRUCT_BEGIN\n/** MDNS answer message structure */\nstruct mdns_auth {\n\tPACK_STRUCT_FIELD(u32_t src);\n}PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n\n#define SIZEOF_MDNS_AUTH 4\nPACK_STRUCT_BEGIN\n/** MDNS service registration message structure */\nstruct mdns_service {\n\tPACK_STRUCT_FIELD(u16_t prior);\n\tPACK_STRUCT_FIELD(u16_t weight);\n\tPACK_STRUCT_FIELD(u16_t port);\n}PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n\n#define SIZEOF_MDNS_SERVICE 6\n\nuint16 PUCK_PORT ;\nos_timer_t mdns_timer;\n/* forward declarations */\nstatic void mdns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p,\n\t\tstruct ip_addr *addr, u16_t port);\n\n/*-----------------------------------------------------------------------------\n * Globales\n *----------------------------------------------------------------------------*/\n\n/* MDNS variables */\nstatic char host_name[MDNS_NAME_LENGTH];\nstatic char service_name[MDNS_NAME_LENGTH];\nstatic char server_name[MDNS_NAME_LENGTH];\n//static char puck_datasheet[PUCK_DATASHEET_SIZE];\nstatic struct udp_pcb *mdns_pcb;\n\nstatic struct ip_addr multicast_addr;\nstatic struct ip_addr host_addr;\nstatic uint8 register_flag = 0;\nstatic uint8 mdns_flag = 0;\n//#if (DNS_USES_STATIC_BUF == 1)\nstatic u8_t mdns_payload[DNS_MSG_SIZE];\n//#endif /* (MDNS_USES_STATIC_BUF == 1) */\n/*\n *  Function to set the UDP pcb used to send the mDNS packages\n */\nvoid ICACHE_FLASH_ATTR\ngetPcb(struct udp_pcb *pcb) {\n\tmdns_pcb = pcb;\n}\n\n#if DNS_DOES_NAME_CHECK\n/**\n * Compare the \"dotted\" name \"query\" with the encoded name \"response\"\n * to make sure an answer from the DNS server matches the current mdns_table\n * entry (otherwise, answers might arrive late for hostname not on the list\n * any more).\n *\n * @param query hostname (not encoded) from the mdns_table\n * @param response encoded hostname in the DNS response\n * @return 0: names equal; 1: names differ\n */\nstatic u8_t ICACHE_FLASH_ATTR\nmdns_compare_name(unsigned char *query, unsigned char *response) {\n\tunsigned char n;\n\n\tdo {\n\t\tn = *response++;\n\t\t/** @see RFC 1035 - 4.1.4. Message compression */\n\t\tif ((n & 0xc0) == 0xc0) {\n\t\t\t/* Compressed name */\n\t\t\tbreak;\n\t\t} else {\n\t\t\t/* Not compressed name */\n\t\t\twhile (n > 0) {\n\t\t\t\tif ((*query) != (*response)) {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\t++response;\n\t\t\t\t++query;\n\t\t\t\t--n;\n\t\t\t};\n\t\t\t++query;\n\t\t}\n\t} while (*response != 0);\n\n\treturn 0;\n}\n#endif /* DNS_DOES_NAME_CHECK */\n/**\n * Send a mDNS answer packet.\n *\n * @param type of answer hostname and service registration or service\n * @param name to query\n * @param id transaction ID in the DNS query packet\n * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise\n */\nstatic err_t ICACHE_FLASH_ATTR\nmdns_answer(u16_t type, const char* name, u8_t id) {\n\terr_t err;\n\tstruct mdns_hdr *hdr;\n\tstruct mdns_answer ans;\n\tstruct mdns_auth auth;\n\tstruct mdns_service serv;\n\tstruct pbuf *p ,*p_sta;\n\tchar *query, *nptr;\n\tconst char *pHostname;\n\tstruct netif * sta_netif = NULL;\n\tstruct netif * ap_netif = NULL;\n\tstatic char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];\n\tu8_t n;\n\tu16_t length = 0;\n\t/* if here, we have either a new query or a retry on a previous query to process */\n\tp = pbuf_alloc(PBUF_TRANSPORT,\n\t\t\tSIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);\n\tif (p != NULL) {\n\t\tLWIP_ASSERT(\"pbuf must be in one piece\", p->next == NULL);\n\t\t/* fill dns header */\n\t\thdr = (struct mdns_hdr*) p->payload;\n\t\tos_memset(hdr, 0, SIZEOF_DNS_HDR);\n\t\thdr->id = htons(id);\n\t\thdr->flags1 = DNS_FLAG1_RESPONSE;\n\n\t\tif (type == MDNS_SD_ANSWER) {\n\t\t\tpHostname = DNS_SD_SERVICE;\n\t\t\thdr->numanswers = htons(1);\n\t\t} else if (type == MDNS_SERVICE_REG_ANSWER) {\n\t\t\tpHostname = PUCK_SERVICE;\n\t\t\thdr->numanswers = htons(type);\n\t\t} else {\n\t\t\tpHostname = name;\n\t\t\thdr->numanswers = htons(type);\n\t\t}\n\t\tquery = (char*) hdr + SIZEOF_DNS_HDR;\n\t\t--pHostname;\n\t\t/* convert hostname into suitable query format. */\n\t\tdo {\n\t\t\t++pHostname;\n\t\t\tnptr = query;\n\t\t\t++query;\n\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t*query = *pHostname;\n\t\t\t\t++query;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\t*nptr = n;\n\t\t} while (*pHostname != 0);\n\t\t*query++ = '\\0';\n\t\t/* fill dns query */\n\n\t\tif (type == MDNS_REG_ANSWER) {\n\n\t\t\tans.type = htons(DNS_RRTYPE_A);\n\t\t\tans.class = htons(DNS_RRCLASS_IN);\n\t\t\tans.ttl = htonl(MDNS_SERVICE_TIME);\n\t\t\tans.len = htons(DNS_IP_ADDR_LEN);\n\t\t\tlength = DNS_IP_ADDR_LEN;\n\n\t\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\n\t\t\t/* resize the query */\n\t\t\tquery = query + SIZEOF_DNS_ANSWER;\n\n\t\t\t/* set the local IP address */\n\t\t\tauth.src = host_addr.addr;\n\t\t\tMEMCPY( query, &auth, SIZEOF_MDNS_AUTH);\n\t\t}\n\t\tif (type == MDNS_SD_ANSWER) {\n\n\t\t\tans.type = htons(DNS_RRTYPE_PTR);\n\t\t\tans.class = htons(DNS_RRCLASS_IN);\n\t\t\tans.ttl = htonl(300);\n\t\t\tans.len = htons(os_strlen(PUCK_SERVICE) + 1 +1 );\n\t\t\tlength = 0;\n\n\t\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\n\t\t\t/* resize the query */\n\t\t\tquery = query + SIZEOF_DNS_ANSWER;\n\t\t\tpHostname = PUCK_SERVICE;\n\t\t\t--pHostname;\n\n\t\t\t/* convert hostname into suitable query format. */\n\t\t\tdo {\n\t\t\t\t++pHostname;\n\t\t\t\tnptr = query;\n\t\t\t\t++query;\n\t\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t\t*query = *pHostname;\n\t\t\t\t\t++query;\n\t\t\t\t\t++n;\n\t\t\t\t}\n\t\t\t\t*nptr = n;\n\t\t\t} while (*pHostname != 0);\n\t\t\t*query++ = '\\0';\n\t\t}\n\n\t\tif (type == MDNS_SERVICE_REG_ANSWER) {\n\n\t\t\tans.type = htons(DNS_RRTYPE_PTR);\n\t\t\tans.class = htons(DNS_RRCLASS_IN);\n\t\t\tans.ttl = htonl(MDNS_SERVICE_TIME);\n\t\t\tos_strcpy(tmpBuf, name);\n\t\t\tos_strcat(tmpBuf, \".\");\n\t\t\tos_strcat(tmpBuf, PUCK_SERVICE);\n\n\t\t\tlength = os_strlen(tmpBuf) + MDNS_LENGTH_ADD;\n\t\t\tans.len = htons(length);\n\t\t\tlength = 0;\n\n\t\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\n\t\t\t/* resize the query */\n\t\t\tquery = query + SIZEOF_DNS_ANSWER;\n\n\t\t\tpHostname = tmpBuf;\n\t\t\t--pHostname;\n\n\t\t\t/* convert hostname into suitable query format. */\n\t\t\tdo {\n\t\t\t\t++pHostname;\n\t\t\t\tnptr = query;\n\t\t\t\t++query;\n\t\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t\t*query = *pHostname;\n\t\t\t\t\t++query;\n\t\t\t\t\t++n;\n\t\t\t\t}\n\t\t\t\t*nptr = n;\n\t\t\t} while (*pHostname != 0);\n\t\t\t*query++ = '\\0';\n\n\t\t\t/* Service query*/\n\t\t\tpHostname = name;\n\t\t\t--pHostname;\n\n\t\t\t/* convert hostname into suitable query format. */\n\t\t\tdo {\n\t\t\t\t++pHostname;\n\t\t\t\tnptr = query;\n\t\t\t\t++query;\n\t\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t\t*query = *pHostname;\n\t\t\t\t\t++query;\n\t\t\t\t\t++n;\n\t\t\t\t}\n\t\t\t\t*nptr = n;\n\t\t\t} while (*pHostname != 0);\n\n\t\t\t/* Add to the service name the service local\n\t\t\t * pointing to the beginning of the mDNS message*/\n\t\t\t*query++ = DNS_OFFSET_FLAG;\n\t\t\t*query++ = DNS_DEFAULT_OFFSET;\n\n\t\t\t/* fill the query */\n\n\t\t\tans.type = htons(DNS_RRTYPE_SRV);\n\t\t\tans.class = htons(DNS_RRCLASS_FLUSH_IN);\n\t\t\tans.ttl = htonl(MDNS_SERVICE_TIME);\n\t\t\tos_strcpy(tmpBuf, host_name);\n\t\t\tos_strcat(tmpBuf, \".\");\n\t\t\tos_strcat(tmpBuf, MDNS_LOCAL);\n\t\t\tlength = os_strlen(tmpBuf) + MDNS_LENGTH_ADD;\n\t\t\tans.len = htons(SIZEOF_MDNS_SERVICE + length);\n\t\t\tlength = 0;\n\t\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\n\t\t\t/* resize the query */\n\t\t\tquery = query + SIZEOF_DNS_ANSWER;\n\t\t\t/* fill the service properties */\n\n\t\t\tserv.prior = htons(0);\n\t\t\tserv.weight = htons(0);\n\t\t\tserv.port = htons(PUCK_PORT);\n\t\t\tMEMCPY( query, &serv, SIZEOF_MDNS_SERVICE);\n\t\t\t/* resize the query */\n\t\t\tquery = query + SIZEOF_MDNS_SERVICE;\n\n\t\t\tpHostname = tmpBuf;\n\t\t\t--pHostname;\n\n\t\t\t/* convert hostname into suitable query format. */\n\t\t\tdo {\n\t\t\t\t++pHostname;\n\t\t\t\tnptr = query;\n\t\t\t\t++query;\n\t\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t\t*query = *pHostname;\n\t\t\t\t\t++query;\n\t\t\t\t\t++n;\n\t\t\t\t}\n\t\t\t\t*nptr = n;\n\t\t\t} while (*pHostname != 0);\n\t\t\t*query++ = '\\0';\n\n\t\t\t/* TXT answer */\n\t\t\tpHostname = name;\n\t\t\t--pHostname;\n\n\t\t\t/* convert hostname into suitable query format. */\n\t\t\tdo {\n\t\t\t\t++pHostname;\n\t\t\t\tnptr = query;\n\t\t\t\t++query;\n\t\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t\t*query = *pHostname;\n\t\t\t\t\t++query;\n\t\t\t\t\t++n;\n\t\t\t\t}\n\t\t\t\t*nptr = n;\n\t\t\t} while (*pHostname != 0);\n\n\t\t\t/* Add to the service name the service local\n\t\t\t * pointing to the beginning of the mDNS message*/\n\t\t\t*query++ = DNS_OFFSET_FLAG;\n\t\t\t*query++ = DNS_DEFAULT_OFFSET;\n\n\t\t\t/* fill the answer */\n\t\t\tans.type = htons(DNS_RRTYPE_TXT);\n\t\t\tans.class = htons(DNS_RRCLASS_IN);\n\t\t\tans.ttl = htonl(MDNS_SERVICE_TIME);\n\t\t\tlength = sizeof(SERVICE_DESCRIPTION);\n\t\t\tans.len = htons(length);\n\t\t\tlength = 0;\n\t\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\n\t\t\t/* resize the query */\n\t\t\tquery = query + SIZEOF_DNS_ANSWER;\n\n\t\t\tpHostname = SERVICE_DESCRIPTION;\n\t\t\t--pHostname;\n\n\t\t\t/* convert hostname into suitable query format. */\n\t\t\tdo {\n\t\t\t\t++pHostname;\n\t\t\t\tnptr = query;\n\t\t\t\t++query;\n\t\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t\t*query = *pHostname;\n\t\t\t\t\t++query;\n\t\t\t\t\t++n;\n\t\t\t\t}\n\t\t\t\t*nptr = n;\n\t\t\t} while (*pHostname != 0);\n\t\t\t*query++ = '\\0';\n\t\t}\n\t\t/* resize pbuf to the exact dns query */\n\t\tpbuf_realloc(p, (query + length) - ((char*) (p->payload)));\n\n\t\t/* send dns packet */\n\t\t/*add by tzx for AP + STA MDNS begin------*/\n\t\tsta_netif = (struct netif *)eagle_lwip_getif(0x00);\n\t\tap_netif =  (struct netif *)eagle_lwip_getif(0x01);\n\t\tif(wifi_get_opmode() == 0x03 && wifi_get_broadcast_if() == 0x03 &&\\\n\t\t\t\tsta_netif != NULL && ap_netif != NULL) {\n\t\t\tif(netif_is_up(sta_netif) && netif_is_up(ap_netif)) {\n\n\t\t\t\tp_sta = pbuf_alloc(PBUF_TRANSPORT,\n\t\t\t\t\t\t\tSIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);\n\t\t\t  if (pbuf_copy (p_sta,p) != ERR_OK) {\n\t\t\t\t  os_printf(\"mdns_answer copying to new pbuf failed\\n\");\n\t\t\t\t  return -1;\n\t\t\t  }\n\t\t\t  netif_set_default(sta_netif);\n\t\t\t  err = udp_sendto(mdns_pcb, p_sta, &multicast_addr, DNS_MDNS_PORT);\n\t\t\t  pbuf_free(p_sta);\n\t\t\t  netif_set_default(ap_netif);\n\t\t\t}\n\t\t}\n\t\t/*add by tzx for AP + STA MDNS end------*/\n\t\terr = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT);\n\t\t/* free pbuf */\n\t\tpbuf_free(p);\n\t} else {\n\t\terr = ERR_MEM;\n\t}\n\n\treturn err;\n}\n\n/**\n * Send a mDNS service answer packet.\n *\n * @param name service name to query\n * @param id transaction ID in the DNS query packet\n * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise\n */\nstatic err_t ICACHE_FLASH_ATTR\nmdns_send_service(struct mdns_info *info, u8_t id) {\n\terr_t err;\n\tstruct mdns_hdr *hdr;\n\tstruct mdns_answer ans;\n\tstruct mdns_service serv;\n\tstruct mdns_auth auth;\n\tstruct pbuf *p ,*p_sta;\n\tchar *query, *nptr;\n\tconst char *pHostname;\n\tchar *device_info;\n\tconst char *name = info->host_name;\n\tu8_t n;\n\tu8_t i = 0;\n\tu16_t length = 0;\n\tu8_t addr1 = 12, addr2 = 12;\n\tstruct netif * sta_netif = NULL;\n\tstruct netif * ap_netif = NULL;\n\tstatic char tmpBuf[PUCK_DATASHEET_SIZE + PUCK_SERVICE_LENGTH];\n\t/* if here, we have either a new query or a retry on a previous query to process */\n\tp = pbuf_alloc(PBUF_TRANSPORT,\n\t\t\tSIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);\n\tif (p != NULL) {\n\t\tLWIP_ASSERT(\"pbuf must be in one piece\", p->next == NULL);\n\t\t/* fill dns header */\n\t\thdr = (struct mdns_hdr*) p->payload;\n\t\tos_memset(hdr, 0, SIZEOF_DNS_HDR);\n\t\thdr->id = htons(id);\n\t\thdr->flags1 = DNS_FLAG1_RESPONSE;\n\t\thdr->numanswers = htons(4);\n\t\tquery = (char*) hdr + SIZEOF_DNS_HDR;\n\t\tos_strcpy(tmpBuf, PUCK_SERVICE);\n\n\t\tpHostname = tmpBuf;\n\t\t--pHostname;\n\n\t\t/* convert hostname into suitable query format. */\n\t\tdo {\n\t\t\t++pHostname;\n\t\t\tnptr = query;\n\t\t\t++query;\n\t\t\t++addr1;\n\t\t\t++addr2;\n\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t*query = *pHostname;\n\t\t\t\t++query;\n\t\t\t\t++addr1;\n\t\t\t\t++addr2;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\t*nptr = n;\n\t\t} while (*pHostname != 0);\n\t\t*query++ = '\\0';\n\t\tlength = sizeof(MDNS_LOCAL);\n\t\taddr1 -= length;\n\t\tlength = os_strlen(PUCK_SERVICE) + 1;\n\t\taddr2 -= length;\n\n\t\tans.type = htons(DNS_RRTYPE_PTR);\n\t\tans.class = htons(DNS_RRCLASS_IN);\n\t\tans.ttl = htonl(300);\n\t\tos_strcpy(tmpBuf, name);\n\t\tlength = os_strlen(tmpBuf) + MDNS_LENGTH_ADD + 1;\n\t\tans.len = htons(length);\n\t\tlength = 0;\n\n\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\t\t/* resize the query */\n\t\tquery = query + SIZEOF_DNS_ANSWER;\n\n\t\tpHostname = tmpBuf;\n\t\t--pHostname;\n\t\t/* convert hostname into suitable query format. */\n\t\tdo {\n\t\t\t++pHostname;\n\t\t\tnptr = query;\n\t\t\t++query;\n\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t*query = *pHostname;\n\t\t\t\t++query;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\t*nptr = n;\n\t\t} while (*pHostname != 0);\n\t\t*query++ = DNS_OFFSET_FLAG;\n\t\t*query++ = DNS_DEFAULT_OFFSET;\n\t\tpHostname = name;\n\t\t--pHostname;\n\t\t/* convert hostname into suitable query format. */\n\t\tdo {\n\t\t\t++pHostname;\n\t\t\tnptr = query;\n\t\t\t++query;\n\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t*query = *pHostname;\n\t\t\t\t++query;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\t*nptr = n;\n\t\t} while (*pHostname != 0);\n\t\t//*query++ = '\\0';\n\t\t*query++ = DNS_OFFSET_FLAG;\n\t\t*query++ = DNS_DEFAULT_OFFSET;\n\n\t\t/* fill the answer */\n\t\tans.type = htons(DNS_RRTYPE_TXT);\n\t\tans.class = htons(DNS_RRCLASS_FLUSH_IN);\n\t\tans.ttl = htonl(300);\n//\t\tlength = os_strlen(TXT_DATA) + MDNS_LENGTH_ADD + 1;\n\t\tdevice_info = (char *)os_zalloc(50);\n\t\tets_sprintf(device_info,\"vendor = %s\",\"Espressif\");\n\t\tfor(i = 0; i < 10 &&(info->txt_data[i] != NULL);i++) {\n\t\t\tlength += os_strlen(info->txt_data[i]);\n\t\t\tlength++;\n\t\t}\n\t\tlength += os_strlen(device_info)+ 1 ;\n\t\tans.len = htons(length);\n\t\tlength = 0;\n\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\t\tquery = query + SIZEOF_DNS_ANSWER;\n\t\tpHostname = device_info;\n\t\t--pHostname;\n\t\t/* convert hostname into suitable query format. */\n\t\tdo {\n\t\t\t++pHostname;\n\t\t\tnptr = query;\n\t\t\t++query;\n\t\t\tfor (n = 0;  *pHostname != 0; ++pHostname) {\n\t\t\t\t*query = *pHostname;\n\t\t\t\t++query;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\t*nptr = n;\n\t\t} while (*pHostname != 0);\n\t\ti = 0;\n\t\twhile(info->txt_data[i] != NULL && i < 10) {\n\t\t\tpHostname = info->txt_data[i];\n\t\t\t--pHostname;\n\t\t\t/* convert hostname into suitable query format. */\n\t\t\tdo {\n\t\t\t\t++pHostname;\n\t\t\t\tnptr = query;\n\t\t\t\t++query;\n\t\t\t\tfor (n = 0;  *pHostname != 0; ++pHostname) {\n\t\t\t\t\t*query = *pHostname;\n\t\t\t\t\t++query;\n\t\t\t\t\t++n;\n\t\t\t\t}\n\t\t\t\t*nptr = n;\n\t\t\t} while (*pHostname != 0);\n\t\t\ti++;\n\t\t}\n//\t\t*query++ = '\\0';\n\t\tos_free(device_info);\n\t\tos_strcpy(tmpBuf, name);\n\t\tpHostname = tmpBuf;\n\t\t--pHostname;\n\t\tdo {\n\t\t\t++pHostname;\n\t\t\tnptr = query;\n\t\t\t++query;\n\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t*query = *pHostname;\n\t\t\t\t++query;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\t*nptr = n;\n\t\t} while (*pHostname != 0);\n\n\t\t*query++ = DNS_OFFSET_FLAG;\n\t\t*query++ = DNS_DEFAULT_OFFSET;\n\n\t\tans.type = htons(DNS_RRTYPE_SRV);\n\t\tans.class = htons(DNS_RRCLASS_FLUSH_IN);\n\t\tans.ttl = htonl(300);\n\t\tos_strcpy(tmpBuf,service_name);\n\t\tos_strcat(tmpBuf, \".\");\n\t\tos_strcat(tmpBuf, MDNS_LOCAL);\n\t\tlength = os_strlen(tmpBuf) + MDNS_LENGTH_ADD;\n\t\tans.len = htons(SIZEOF_MDNS_SERVICE + length);\n\t\tlength = 0;\n\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\n\t\t/* resize the query */\n\t\tquery = query + SIZEOF_DNS_ANSWER;\n\n\t\tserv.prior = htons(0);\n\t\tserv.weight = htons(0);\n\t\tserv.port = htons(PUCK_PORT);\n\t\tMEMCPY( query, &serv, SIZEOF_MDNS_SERVICE);\n\t\t/* resize the query */\n\t\tquery = query + SIZEOF_MDNS_SERVICE;\n\n\t\tpHostname = tmpBuf;\n\t\t--pHostname;\n\t\tdo {\n\t\t\t++pHostname;\n\t\t\tnptr = query;\n\t\t\t++query;\n\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t*query = *pHostname;\n\t\t\t\t++query;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\t*nptr = n;\n\t\t} while (*pHostname != 0);\n\t\t*query++ = '\\0';\n\t\t/* set the name of the authority field.\n\t\t * The same name as the Query using the offset address*/\n\t\tos_strcpy(tmpBuf,service_name);\n\t\tos_strcat(tmpBuf, \".\");\n\t\tos_strcat(tmpBuf, MDNS_LOCAL);\n\t\tpHostname = tmpBuf;\n\t\t--pHostname;\n\t\tdo {\n\t\t\t++pHostname;\n\t\t\tnptr = query;\n\t\t\t++query;\n\t\t\tfor (n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\n\t\t\t\t*query = *pHostname;\n\t\t\t\t++query;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\t*nptr = n;\n\t\t} while (*pHostname != 0);\n\t\t*query++ = '\\0';\n\t\t/* set the name of the authority field.\n\t\t * The same name as the Query using the offset address*/\n\t\t//*query++ = DNS_OFFSET_FLAG;\n\t\t//*query++ = DNS_DEFAULT_OFFSET;\n\t\tans.type = htons(DNS_RRTYPE_A);\n\t\tans.class = htons(DNS_RRCLASS_FLUSH_IN);\n\t\tans.ttl = htonl(300);\n\t\tans.len = htons(DNS_IP_ADDR_LEN);\n\n\t\tMEMCPY( query, &ans, SIZEOF_DNS_ANSWER);\n\n\t\t/* resize the query */\n\t\tquery = query + SIZEOF_DNS_ANSWER;\n\n\t\t/* fill the payload of the mDNS message */\n\t\t/* set the local IP address */\n\t\tauth.src = host_addr.addr; //ipAddr;\n\t\tMEMCPY( query, &auth, SIZEOF_MDNS_AUTH);\n\t\t/* resize the query */\n\t\tquery = query + SIZEOF_MDNS_AUTH;\n\n\t\t/* set the name of the authority field.\n\t\t * The same name as the Query using the offset address*/\n\n\t\t/* resize pbuf to the exact dns query */\n\t\tpbuf_realloc(p, (query) - ((char*) (p->payload)));\n\t\t/* send dns packet */\n\t\tsta_netif = (struct netif *)eagle_lwip_getif(0x00);\n\t\tap_netif =  (struct netif *)eagle_lwip_getif(0x01);\n\t\tif(wifi_get_opmode() == 0x03 && wifi_get_broadcast_if() == 0x03 &&\\\n\t\t\t\tsta_netif != NULL && ap_netif != NULL) {\n\t\t\tif(netif_is_up(sta_netif) && netif_is_up(ap_netif)) {\n\n\t\t\t\tp_sta = pbuf_alloc(PBUF_TRANSPORT,\n\t\t\t\t\t\t\tSIZEOF_DNS_HDR + MDNS_MAX_NAME_LENGTH * 2 + SIZEOF_DNS_QUERY, PBUF_RAM);\n\t\t\t  if (pbuf_copy (p_sta,p) != ERR_OK) {\n\t\t\t\t  os_printf(\"mdns_send_service copying to new pbuf failed\\n\");\n\t\t\t\t  return -1;\n\t\t\t  }\n\t\t\t  netif_set_default(sta_netif);\n\t\t\t  err = udp_sendto(mdns_pcb, p_sta, &multicast_addr, DNS_MDNS_PORT);\n\t\t\t  pbuf_free(p_sta);\n\t\t\t  netif_set_default(ap_netif);\n\t\t\t}\n\t\t}\n\t\terr = udp_sendto(mdns_pcb, p, &multicast_addr, DNS_MDNS_PORT);\n\n\t\t/* free pbuf */\n\t\tpbuf_free(p);\n\t} else {\n\t\tos_printf(\"ERR_MEM \\n\");\n\t\terr = ERR_MEM;\n\t}\n\n\treturn err;\n}\n\n/**\n * Receive input function for DNS response packets arriving for the dns UDP pcb.\n *\n * @params see udp.h\n */\nstatic void ICACHE_FLASH_ATTR\nmdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr,\n\t\tu16_t port) {\n\tu8_t i;\n\tstruct mdns_hdr *hdr;\n\tu8_t nquestions;\n\tLWIP_UNUSED_ARG(arg);\n\tLWIP_UNUSED_ARG(pcb);\n\tLWIP_UNUSED_ARG(addr);\n\tLWIP_UNUSED_ARG(port);\n\tstruct mdns_info *info = (struct mdns_info *)arg;\n\t/* is the dns message too big ? */\n\tif (p->tot_len > DNS_MSG_SIZE) {\n\t\tLWIP_DEBUGF(DNS_DEBUG, (\"dns_recv: pbuf too big\\n\"));\n\t\t/* free pbuf and return */\n\t\tgoto memerr1;\n\t}\n\n\t/* is the dns message big enough ? */\n\tif (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {\n\t\tLWIP_DEBUGF(DNS_DEBUG, (\"dns_recv: pbuf too small\\n\"));\n\t\t/* free pbuf and return */\n\t\tgoto memerr1;\n\t}\n\t/* copy dns payload inside static buffer for processing */\n\tif (pbuf_copy_partial(p, mdns_payload, p->tot_len, 0) == p->tot_len) {\n\t\t/* The ID in the DNS header should be our entry into the name table. */\n\t\thdr = (struct mdns_hdr*) mdns_payload;\n\n\t\ti = htons(hdr->id);\n\t\tif (i < DNS_TABLE_SIZE) {\n\n\t\t\tnquestions = htons(hdr->numquestions);\n\t\t\t//nanswers   = htons(hdr->numanswers);\n\t\t\t/* if we have a question send an answer if necessary */\n\t\t\tif (nquestions > 0) {\n\t\t\t\t/* MDNS_DS_DOES_NAME_CHECK */\n\t\t\t\t/* Check if the name in the \"question\" part match with the name of the MDNS DS service. */\n\t\t\t\tif (mdns_compare_name((unsigned char *) DNS_SD_SERVICE,\n\t\t\t\t\t\t(unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) {\n\t\t\t\t\t/* respond with the puck service*/\n\t\t\t\t\tmdns_answer(MDNS_SD_ANSWER, PUCK_SERVICE, 0);\n\t\t\t\t} else if (mdns_compare_name((unsigned char *) PUCK_SERVICE,\n\t\t\t\t\t\t(unsigned char *) mdns_payload + SIZEOF_DNS_HDR) == 0) {\n\t\t\t\t\t/* respond with the puck service*/\n\t\t\t\t\tmdns_send_service(info, 0);\n\t\t\t\t} else\n\t\t\t\t\tgoto memerr2;\n\t\t\t}\n\t\t}\n\t}\n\tgoto memerr2;\n\tmemerr2:\n\tmem_free(mdns_payload);\n\tmemerr1:\n\t/* free pbuf */\n\tpbuf_free(p);\n\treturn;\n}\n\n/**\n * close the UDP pcb .\n */\nvoid ICACHE_FLASH_ATTR\nmdns_close(void)\n{\n\tif (mdns_pcb != NULL)\n\t\tudp_remove(mdns_pcb);\n}\n\nvoid ICACHE_FLASH_ATTR\nmdns_set_name(const char *name)\n{\n\t//strcpy(host_name, name);\n\tos_strcpy(service_name, name);\n}\n\nvoid ICACHE_FLASH_ATTR\nmdns_enable(void)\n{\n\tif(mdns_flag == 0) {\n\t\tudp_recv(mdns_pcb, mdns_recv, NULL);\n\t}\n}\n\nvoid ICACHE_FLASH_ATTR\nmdns_disable(void)\n{\n\tif (mdns_flag == 1) {\n\t\tudp_recv(mdns_pcb, NULL, NULL);\n\t}\n}\n\n/**\n * close the UDP pcb .\n */\nchar* ICACHE_FLASH_ATTR\nmdns_get_hostname(void) {\n\t//strcpy(host_name, name);\n\tchar *name = host_name;\n\tif (host_name[0] != 0 ) {\n\treturn name;\n\t} else {\n\t\treturn (\"Espressif\");\n\t}\n}\n\nvoid ICACHE_FLASH_ATTR\nmdns_set_hostname(char *name) {\n\tif (name == NULL) {\n\t\tos_strncpy(host_name, \"Espressif\", os_strlen(\"Espressif\")+3);\n\t\treturn;\n\t}\n\tif (os_strlen(name) + 3 <= MDNS_NAME_LENGTH ){\n\t\tos_strncpy(host_name, name, os_strlen(name) );\n//\t\tos_memset(host_name + os_strlen(host_name) ,0x00,3);\n\t} else {\n\t\tos_strncpy(host_name, name, MDNS_NAME_LENGTH);\n\t}\n}\n\nvoid ICACHE_FLASH_ATTR\nmdns_set_servername(const char *name) {\n\tif (name == NULL) {\n\t\tPUCK_SERVICE = \"_Espressif._tcp._local\";\n\t}else {\n\t\tos_sprintf(server_name ,\"_%s._tcp.local\",name);\n\t\tPUCK_SERVICE = server_name;\n\t}\n}\n\nchar* ICACHE_FLASH_ATTR\nmdns_get_servername(void) {\n\tchar *name = PUCK_SERVICE;\n\tif (name == NULL) {\n\t\tPUCK_SERVICE = \"_Espressif._tcp._local\";\n\t}\n\treturn name;\n}\n\nvoid ICACHE_FLASH_ATTR\nmdns_server_unregister(void) {\n\tstruct ip_addr ap_host_addr;\n\tstruct ip_info ipconfig;\n\tif(register_flag == 1){\n\t\tif (igmp_leavegroup(&host_addr, &multicast_addr) != ERR_OK) {\n\t\t\tos_printf(\"sta udp_leave_multigrup failed!\\n\");\n\t\t\treturn;\n\t\t};\n\t\tif(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x02) {\n\t\t   wifi_get_ip_info(SOFTAP_IF, &ipconfig);\n\t\t   ap_host_addr.addr = ipconfig.ip.addr;\n\t\t   if (igmp_leavegroup(&ap_host_addr, &multicast_addr) != ERR_OK) {\n\t\t\t\tos_printf(\"ap udp_join_multigrup failed!\\n\");\n\t\t\t\treturn;\n\t\t\t};\n\t\t}\n\t\tregister_flag = 0;\n\t}\n}\n\nvoid ICACHE_FLASH_ATTR\nmdns_server_register(void) {\n\n\tif (register_flag == 1) {\n\t\tos_printf(\"mdns server is already registered !\\n\");\n\t\treturn;\n\t} else if (igmp_joingroup(&host_addr, &multicast_addr) != ERR_OK) {\n\t\tos_printf(\"udp_join_multigrup failed!\\n\");\n\t\treturn;\n\t};\n\tregister_flag = 1;\n}\n\nvoid ICACHE_FLASH_ATTR\nmdns_reg(struct mdns_info *info) {\n\n   static uint8 i = 0;\n   if (i <= 3) {\n\t   mdns_send_service(info,0);\n\t   i++;\n   } else {\n\t   os_timer_disarm(&mdns_timer);\n   }\n}\n\n/**\n * Initialize the resolver: set up the UDP pcb and configure the default server\n * (NEW IP).\n */\nvoid ICACHE_FLASH_ATTR\nmdns_init(struct mdns_info *info) {\n\t/* initialize default DNS server address */\n\tmulticast_addr.addr = DNS_MULTICAST_ADDRESS;\n\tstruct ip_addr ap_host_addr;\n\tstruct ip_info ipconfig;\n\tif (info->ipAddr == 0) {\n\t\tos_printf(\"mdns ip error!\\n \");\n\t\treturn;\n\t}\n\thost_addr.addr = info->ipAddr ;\n\tLWIP_DEBUGF(DNS_DEBUG, (\"dns_init: initializing\\n\"));\n\t//get the datasheet from PUCK\n\tmdns_set_hostname(info->host_name);\n\tmdns_set_servername(info->server_name);\n\tmdns_set_name(info->host_name);\n\n\t// get the host name as instrumentName_serialNumber for MDNS\n\t// set the name of the service, the same as host name\n\tos_printf(\"host_name = %s\\n\", host_name);\n\tos_printf(\"server_name = %s\\n\", PUCK_SERVICE);\n\tif (info->server_port == 0)\n\t{\n\t\tPUCK_PORT = 80;\n\t} else {\n\t\tPUCK_PORT = info->server_port;\n\t}\n\n\t/* initialize mDNS */\n\tmdns_pcb = udp_new();\n\n\tif (mdns_pcb != NULL) {\n\t\t/* join to the multicast address 224.0.0.251 */\n\t\tif(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x01) {\n\t\t\tif (igmp_joingroup(&host_addr, &multicast_addr) != ERR_OK) {\n\t\t\t\tos_printf(\"sta udp_join_multigrup failed!\\n\");\n\t\t\t\treturn;\n\t\t\t};\n\t\t}\n\t\tif(wifi_get_opmode() == 0x03 || wifi_get_opmode() == 0x02) {\n\t\t   wifi_get_ip_info(SOFTAP_IF, &ipconfig);\n\t\t   ap_host_addr.addr = ipconfig.ip.addr;\n\t\t   if (igmp_joingroup(&ap_host_addr, &multicast_addr) != ERR_OK) {\n\t\t\t\tos_printf(\"ap udp_join_multigrup failed!\\n\");\n\t\t\t\treturn;\n\t\t\t};\n\t\t}\n\t\tregister_flag = 1;\n\t\t/* join to any IP address at the port 5353 */\n\t\tif (udp_bind(mdns_pcb, IP_ADDR_ANY, DNS_MDNS_PORT) != ERR_OK) {\n\t\t\tos_printf(\"udp_bind failed!\\n\");\n\t\t\treturn;\n\t\t};\n\n\t\t/*loopback function for the multicast(224.0.0.251) messages received at port 5353*/\n//\t\tmdns_enable();\n\t\tudp_recv(mdns_pcb, mdns_recv, info);\n\t\tmdns_flag = 1;\n\t\t/*\n\t\t * Register the name of the instrument\n\t\t */\n\n\t\tos_timer_disarm(&mdns_timer);\n\t\tos_timer_setfn(&mdns_timer, (os_timer_func_t *)mdns_reg,info);\n\t\tos_timer_arm(&mdns_timer, 1000, 1);\n\t}\n}\n\n#endif /* LWIP_MDNS */\n"
  },
  {
    "path": "app/lwip/core/mem.c",
    "content": "/**\n * @file\n * Dynamic memory manager\n *\n * This is a lightweight replacement for the standard C library malloc().\n *\n * If you want to use the standard C library malloc() instead, define\n * MEM_LIBC_MALLOC to 1 in your lwipopts.h\n *\n * To let mem_malloc() use pools (prevents fragmentation and is much faster than\n * a heap but might waste some memory), define MEM_USE_POOLS to 1, define\n * MEM_USE_CUSTOM_POOLS to 1 and create a file \"lwippools.h\" that includes a list\n * of pools like this (more pools can be added between _START and _END):\n *\n * Define three pools with sizes 256, 512, and 1512 bytes\n * LWIP_MALLOC_MEMPOOL_START\n * LWIP_MALLOC_MEMPOOL(20, 256)\n * LWIP_MALLOC_MEMPOOL(10, 512)\n * LWIP_MALLOC_MEMPOOL(5, 1512)\n * LWIP_MALLOC_MEMPOOL_END\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *         Simon Goldschmidt\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/def.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/err.h\"\n\n#include <string.h>\n\n#if MEM_USE_POOLS\n/* lwIP head implemented with different sized pools */\n\n/**\n * Allocate memory: determine the smallest pool that is big enough\n * to contain an element of 'size' and get an element from that pool.\n *\n * @param size the size in bytes of the memory needed\n * @return a pointer to the allocated memory or NULL if the pool is empty\n */\nvoid *\nmem_malloc(mem_size_t size)\n{\n  struct memp_malloc_helper *element;\n  memp_t poolnr;\n  mem_size_t required_size = size + sizeof(struct memp_malloc_helper);\n\n  for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {\n#if MEM_USE_POOLS_TRY_BIGGER_POOL\nagain:\n#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */\n    /* is this pool big enough to hold an element of the required size\n       plus a struct memp_malloc_helper that saves the pool this element came from? */\n    if (required_size <= memp_sizes[poolnr]) {\n      break;\n    }\n  }\n  if (poolnr > MEMP_POOL_LAST) {\n    LWIP_ASSERT(\"mem_malloc(): no pool is that big!\", 0);\n    return NULL;\n  }\n  element = (struct memp_malloc_helper*)memp_malloc(poolnr);\n  if (element == NULL) {\n    /* No need to DEBUGF or ASSERT: This error is already\n       taken care of in memp.c */\n#if MEM_USE_POOLS_TRY_BIGGER_POOL\n    /** Try a bigger pool if this one is empty! */\n    if (poolnr < MEMP_POOL_LAST) {\n      poolnr++;\n      goto again;\n    }\n#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */\n    return NULL;\n  }\n\n  /* save the pool number this element came from */\n  element->poolnr = poolnr;\n  /* and return a pointer to the memory directly after the struct memp_malloc_helper */\n  element++;\n\n  return element;\n}\n\n/**\n * Free memory previously allocated by mem_malloc. Loads the pool number\n * and calls memp_free with that pool number to put the element back into\n * its pool\n *\n * @param rmem the memory element to free\n */\nvoid\nmem_free(void *rmem)\n{\n  struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;\n\n  LWIP_ASSERT(\"rmem != NULL\", (rmem != NULL));\n  LWIP_ASSERT(\"rmem == MEM_ALIGN(rmem)\", (rmem == LWIP_MEM_ALIGN(rmem)));\n\n  /* get the original struct memp_malloc_helper */\n  hmem--;\n\n  LWIP_ASSERT(\"hmem != NULL\", (hmem != NULL));\n  LWIP_ASSERT(\"hmem == MEM_ALIGN(hmem)\", (hmem == LWIP_MEM_ALIGN(hmem)));\n  LWIP_ASSERT(\"hmem->poolnr < MEMP_MAX\", (hmem->poolnr < MEMP_MAX));\n\n  /* and put it in the pool we saved earlier */\n  memp_free(hmem->poolnr, hmem);\n}\n\n#else /* MEM_USE_POOLS */\n/* lwIP replacement for your libc malloc() */\n\n/**\n * The heap is made up as a list of structs of this type.\n * This does not have to be aligned since for getting its size,\n * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.\n */\nstruct mem {\n  /** index (-> ram[next]) of the next struct */\n  mem_size_t next;\n  /** index (-> ram[prev]) of the previous struct */\n  mem_size_t prev;\n  /** 1: this area is used; 0: this area is unused */\n  u8_t used;\n  u8_t pad[3];  /* XXX: pad here instead use global ALIGN */\n} __ATTRIB_PACK;\n\n/** All allocated blocks will be MIN_SIZE bytes big, at least!\n * MIN_SIZE can be overridden to suit your needs. Smaller values save space,\n * larger values could prevent too small blocks to fragment the RAM too much. */\n#ifndef MIN_SIZE\n#define MIN_SIZE             12\n#endif /* MIN_SIZE */\n/* some alignment macros: we define them here for better source code layout */\n#define MIN_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MIN_SIZE)\n#define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))\n#define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)\n\n/** If you want to relocate the heap to external memory, simply define\n * LWIP_RAM_HEAP_POINTER as a void-pointer to that location.\n * If so, make sure the memory at that location is big enough (see below on\n * how that space is calculated). */\n#ifndef LWIP_RAM_HEAP_POINTER\n/** the heap. we need one struct mem at the end and some room for alignment */\n/* enlarge heap as tx pbuf payload is allocate from heap as well */\nu8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT] SHMEM_ATTR;\n#define LWIP_RAM_HEAP_POINTER ram_heap\n#endif /* LWIP_RAM_HEAP_POINTER */\n\n/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */\nstatic u8_t *ram;\n/** the last entry, always unused! */\nstatic struct mem *ram_end;\n/** pointer to the lowest free block, this is used for faster search */\nstatic struct mem *lfree;\n\n/** concurrent access protection */\n//static sys_mutex_t mem_mutex;\n\n#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n\nstatic volatile u8_t mem_free_count;\n\n/* Allow mem_free from other (e.g. interrupt) context */\n#define LWIP_MEM_FREE_DECL_PROTECT()  SYS_ARCH_DECL_PROTECT(lev_free)\n#define LWIP_MEM_FREE_PROTECT()       SYS_ARCH_PROTECT(lev_free)\n#define LWIP_MEM_FREE_UNPROTECT()     SYS_ARCH_UNPROTECT(lev_free)\n#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)\n#define LWIP_MEM_ALLOC_PROTECT()      SYS_ARCH_PROTECT(lev_alloc)\n#define LWIP_MEM_ALLOC_UNPROTECT()    SYS_ARCH_UNPROTECT(lev_alloc)\n\n#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */\n\n/* Protect the heap only by using a semaphore */\n#define LWIP_MEM_FREE_DECL_PROTECT()\n#define LWIP_MEM_FREE_PROTECT()    sys_mutex_lock(&mem_mutex)\n#define LWIP_MEM_FREE_UNPROTECT()  sys_mutex_unlock(&mem_mutex)\n/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */\n#define LWIP_MEM_ALLOC_DECL_PROTECT()\n#define LWIP_MEM_ALLOC_PROTECT()\n#define LWIP_MEM_ALLOC_UNPROTECT()\n\n#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */\n\n\n/**\n * \"Plug holes\" by combining adjacent empty struct mems.\n * After this function is through, there should not exist\n * one empty struct mem pointing to another empty struct mem.\n *\n * @param mem this points to a struct mem which just has been freed\n * @internal this function is only called by mem_free() and mem_trim()\n *\n * This assumes access to the heap is protected by the calling function\n * already.\n */\nstatic void ICACHE_FLASH_ATTR\nplug_holes(struct mem *mem)\n{\n  struct mem *nmem;\n  struct mem *pmem;\n\n  LWIP_ASSERT(\"plug_holes: mem >= ram\", (u8_t *)mem >= ram);\n  LWIP_ASSERT(\"plug_holes: mem < ram_end\", (u8_t *)mem < (u8_t *)ram_end);\n  LWIP_ASSERT(\"plug_holes: mem->used == 0\", mem->used == 0);\n\n  /* plug hole forward */\n  LWIP_ASSERT(\"plug_holes: mem->next <= MEM_SIZE_ALIGNED\", mem->next <= MEM_SIZE_ALIGNED);\n\n  nmem = (struct mem *)(void *)&ram[mem->next];\n  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {\n    /* if mem->next is unused and not end of ram, combine mem and mem->next */\n    if (lfree == nmem) {\n      lfree = mem;\n    }\n    mem->next = nmem->next;\n    ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram);\n  }\n\n  /* plug hole backward */\n  pmem = (struct mem *)(void *)&ram[mem->prev];\n  if (pmem != mem && pmem->used == 0) {\n    /* if mem->prev is unused, combine mem and mem->prev */\n    if (lfree == mem) {\n      lfree = pmem;\n    }\n    pmem->next = mem->next;\n    ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram);\n  }\n}\n\n/**\n * Zero the heap and initialize start, end and lowest-free\n */\nvoid\nmem_init(void)\n{\n  struct mem *mem;\n\n  LWIP_ASSERT(\"Sanity check alignment\",\n    (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);\n\n  /* align the heap */\n  ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);\n  /* initialize the start of the heap */\n  mem = (struct mem *)(void *)ram;\n  mem->next = MEM_SIZE_ALIGNED;\n  mem->prev = 0;\n  mem->used = 0;\n  /* initialize the end of the heap */\n  ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED];\n  ram_end->used = 1;\n  ram_end->next = MEM_SIZE_ALIGNED;\n  ram_end->prev = MEM_SIZE_ALIGNED;\n\n  /* initialize the lowest-free pointer to the start of the heap */\n  lfree = (struct mem *)(void *)ram;\n\n  MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);\n\n  if(sys_mutex_new(&mem_mutex) != ERR_OK) {\n    LWIP_ASSERT(\"failed to create mem_mutex\", 0);\n  }\n}\n\n/**\n * Put a struct mem back on the heap\n *\n * @param rmem is the data portion of a struct mem as returned by a previous\n *             call to mem_malloc()\n */\nvoid\nmem_free(void *rmem)\n{\n  struct mem *mem;\n  LWIP_MEM_FREE_DECL_PROTECT();\n\n  if (rmem == NULL) {\n    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"mem_free(p == NULL) was called.\\n\"));\n    return;\n  }\n  LWIP_ASSERT(\"mem_free: sanity check alignment\", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);\n\n  LWIP_ASSERT(\"mem_free: legal memory\", (u8_t *)rmem >= (u8_t *)ram &&\n    (u8_t *)rmem < (u8_t *)ram_end);\n\n  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {\n    SYS_ARCH_DECL_PROTECT(lev);\n    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, (\"mem_free: illegal memory\\n\"));\n    /* protect mem stats from concurrent access */\n    SYS_ARCH_PROTECT(lev);\n    MEM_STATS_INC(illegal);\n    SYS_ARCH_UNPROTECT(lev);\n    return;\n  }\n  /* protect the heap from concurrent access */\n  LWIP_MEM_FREE_PROTECT();\n  /* Get the corresponding struct mem ... */\n  mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);\n  /* ... which has to be in a used state ... */\n  LWIP_ASSERT(\"mem_free: mem->used\", mem->used);\n  /* ... and is now unused. */\n  mem->used = 0;\n\n  if (mem < lfree) {\n    /* the newly freed struct is now the lowest */\n    lfree = mem;\n  }\n\n  MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));\n\n  /* finally, see if prev or next are free also */\n  plug_holes(mem);\n#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n  mem_free_count = 1;\n#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */\n  LWIP_MEM_FREE_UNPROTECT();\n}\n\n/**\n * Shrink memory returned by mem_malloc().\n *\n * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked\n * @param newsize required size after shrinking (needs to be smaller than or\n *                equal to the previous size)\n * @return for compatibility reasons: is always == rmem, at the moment\n *         or NULL if newsize is > old size, in which case rmem is NOT touched\n *         or freed!\n */\nvoid *\nmem_trim(void *rmem, mem_size_t newsize)\n{\n  mem_size_t size;\n  mem_size_t ptr, ptr2;\n  struct mem *mem, *mem2;\n  /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */\n  LWIP_MEM_FREE_DECL_PROTECT();\n\n  /* Expand the size of the allocated memory region so that we can\n     adjust for alignment. */\n  newsize = LWIP_MEM_ALIGN_SIZE(newsize);\n\n  if(newsize < MIN_SIZE_ALIGNED) {\n    /* every data block must be at least MIN_SIZE_ALIGNED long */\n    newsize = MIN_SIZE_ALIGNED;\n  }\n\n  if (newsize > MEM_SIZE_ALIGNED) {\n    return NULL;\n  }\n\n  LWIP_ASSERT(\"mem_trim: legal memory\", (u8_t *)rmem >= (u8_t *)ram &&\n   (u8_t *)rmem < (u8_t *)ram_end);\n\n  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {\n    SYS_ARCH_DECL_PROTECT(lev);\n    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, (\"mem_trim: illegal memory\\n\"));\n    /* protect mem stats from concurrent access */\n    SYS_ARCH_PROTECT(lev);\n    MEM_STATS_INC(illegal);\n    SYS_ARCH_UNPROTECT(lev);\n    return rmem;\n  }\n  /* Get the corresponding struct mem ... */\n  mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);\n  /* ... and its offset pointer */\n  ptr = (mem_size_t)((u8_t *)mem - ram);\n\n  size = mem->next - ptr - SIZEOF_STRUCT_MEM;\n  LWIP_ASSERT(\"mem_trim can only shrink memory\", newsize <= size);\n  if (newsize > size) {\n    /* not supported */\n    return NULL;\n  }\n  if (newsize == size) {\n    /* No change in size, simply return */\n    return rmem;\n  }\n\n  /* protect the heap from concurrent access */\n  LWIP_MEM_FREE_PROTECT();\n\n  mem2 = (struct mem *)(void *)&ram[mem->next];\n  if(mem2->used == 0) {\n    /* The next struct is unused, we can simply move it at little */\n    mem_size_t next;\n    /* remember the old next pointer */\n    next = mem2->next;\n    /* create new struct mem which is moved directly after the shrinked mem */\n    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;\n    if (lfree == mem2) {\n      lfree = (struct mem *)(void *)&ram[ptr2];\n    }\n    mem2 = (struct mem *)(void *)&ram[ptr2];\n    mem2->used = 0;\n    /* restore the next pointer */\n    mem2->next = next;\n    /* link it back to mem */\n    mem2->prev = ptr;\n    /* link mem to it */\n    mem->next = ptr2;\n    /* last thing to restore linked list: as we have moved mem2,\n     * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not\n     * the end of the heap */\n    if (mem2->next != MEM_SIZE_ALIGNED) {\n      ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;\n    }\n    MEM_STATS_DEC_USED(used, (size - newsize));\n    /* no need to plug holes, we've already done that */\n  } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {\n    /* Next struct is used but there's room for another struct mem with\n     * at least MIN_SIZE_ALIGNED of data.\n     * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem\n     * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').\n     * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty\n     *       region that couldn't hold data, but when mem->next gets freed,\n     *       the 2 regions would be combined, resulting in more free memory */\n    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;\n    mem2 = (struct mem *)(void *)&ram[ptr2];\n    if (mem2 < lfree) {\n      lfree = mem2;\n    }\n    mem2->used = 0;\n    mem2->next = mem->next;\n    mem2->prev = ptr;\n    mem->next = ptr2;\n    if (mem2->next != MEM_SIZE_ALIGNED) {\n      ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;\n    }\n    MEM_STATS_DEC_USED(used, (size - newsize));\n    /* the original mem->next is used, so no need to plug holes! */\n  }\n  /* else {\n    next struct mem is used but size between mem and mem2 is not big enough\n    to create another struct mem\n    -> don't do anyhting. \n    -> the remaining space stays unused since it is too small\n  } */\n#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n  mem_free_count = 1;\n#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */\n  LWIP_MEM_FREE_UNPROTECT();\n  return rmem;\n}\n\n/**\n * Adam's mem_malloc() plus solution for bug #17922\n * Allocate a block of memory with a minimum of 'size' bytes.\n *\n * @param size is the minimum size of the requested block in bytes.\n * @return pointer to allocated memory or NULL if no free memory was found.\n *\n * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).\n */\nvoid *\nmem_malloc(mem_size_t size)\n{\n  mem_size_t ptr, ptr2;\n  struct mem *mem, *mem2;\n#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n  u8_t local_mem_free_count = 0;\n#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */\n  LWIP_MEM_ALLOC_DECL_PROTECT();\n\n  if (size == 0) {\n    return NULL;\n  }\n\n  /* Expand the size of the allocated memory region so that we can\n     adjust for alignment. */\n  size = LWIP_MEM_ALIGN_SIZE(size);\n\n  if(size < MIN_SIZE_ALIGNED) {\n    /* every data block must be at least MIN_SIZE_ALIGNED long */\n    size = MIN_SIZE_ALIGNED;\n  }\n\n  if (size > MEM_SIZE_ALIGNED) {\n    return NULL;\n  }\n\n  /* protect the heap from concurrent access */\n  sys_mutex_lock(&mem_mutex);\n  LWIP_MEM_ALLOC_PROTECT();\n#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n  /* run as long as a mem_free disturbed mem_malloc */\n  do {\n    local_mem_free_count = 0;\n#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */\n\n    /* Scan through the heap searching for a free block that is big enough,\n     * beginning with the lowest free block.\n     */\n    for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size;\n         ptr = ((struct mem *)(void *)&ram[ptr])->next) {\n      mem = (struct mem *)(void *)&ram[ptr];\n#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n      mem_free_count = 0;\n      LWIP_MEM_ALLOC_UNPROTECT();\n      /* allow mem_free to run */\n      LWIP_MEM_ALLOC_PROTECT();\n      if (mem_free_count != 0) {\n        local_mem_free_count = mem_free_count;\n      }\n      mem_free_count = 0;\n#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */\n\n      if ((!mem->used) &&\n          (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {\n        /* mem is not used and at least perfect fit is possible:\n         * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */\n\n        if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {\n          /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing\n           * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')\n           * -> split large block, create empty remainder,\n           * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if\n           * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,\n           * struct mem would fit in but no data between mem2 and mem2->next\n           * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty\n           *       region that couldn't hold data, but when mem->next gets freed,\n           *       the 2 regions would be combined, resulting in more free memory\n           */\n          ptr2 = ptr + SIZEOF_STRUCT_MEM + size;\n          /* create mem2 struct */\n          mem2 = (struct mem *)(void *)&ram[ptr2];\n          mem2->used = 0;\n          mem2->next = mem->next;\n          mem2->prev = ptr;\n          /* and insert it between mem and mem->next */\n          mem->next = ptr2;\n          mem->used = 1;\n\n          if (mem2->next != MEM_SIZE_ALIGNED) {\n            ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;\n          }\n          MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));\n        } else {\n          /* (a mem2 struct does no fit into the user data space of mem and mem->next will always\n           * be used at this point: if not we have 2 unused structs in a row, plug_holes should have\n           * take care of this).\n           * -> near fit or excact fit: do not split, no mem2 creation\n           * also can't move mem->next directly behind mem, since mem->next\n           * will always be used at this point!\n           */\n          mem->used = 1;\n          MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));\n        }\n\n        if (mem == lfree) {\n          /* Find next free block after mem and update lowest free pointer */\n          while (lfree->used && lfree != ram_end) {\n            LWIP_MEM_ALLOC_UNPROTECT();\n            /* prevent high interrupt latency... */\n            LWIP_MEM_ALLOC_PROTECT();\n            lfree = (struct mem *)(void *)&ram[lfree->next];\n          }\n          LWIP_ASSERT(\"mem_malloc: !lfree->used\", ((lfree == ram_end) || (!lfree->used)));\n        }\n        LWIP_MEM_ALLOC_UNPROTECT();\n        sys_mutex_unlock(&mem_mutex);\n        LWIP_ASSERT(\"mem_malloc: allocated memory not above ram_end.\",\n         (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);\n        LWIP_ASSERT(\"mem_malloc: allocated memory properly aligned.\",\n         ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);\n        LWIP_ASSERT(\"mem_malloc: sanity check alignment\",\n          (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);\n\n        return (u8_t *)mem + SIZEOF_STRUCT_MEM;\n      }\n    }\n#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT\n    /* if we got interrupted by a mem_free, try again */\n  } while(local_mem_free_count != 0);\n#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */\n  LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"mem_malloc: could not allocate %\"S16_F\" bytes\\n\", (s16_t)size));\n  MEM_STATS_INC(err);\n  LWIP_MEM_ALLOC_UNPROTECT();\n  sys_mutex_unlock(&mem_mutex);\n  return NULL;\n}\n\n#endif /* MEM_USE_POOLS */\n/**\n * Contiguously allocates enough space for count objects that are size bytes\n * of memory each and returns a pointer to the allocated memory.\n *\n * The allocated memory is filled with bytes of value zero.\n *\n * @param count number of objects to allocate\n * @param size size of the objects to allocate\n * @return pointer to allocated memory / NULL pointer if there is an error\n */\nvoid *mem_calloc(mem_size_t count, mem_size_t size)\n{\n  void *p;\n\n  /* allocate 'count' objects of size 'size' */\n  p = mem_malloc(count * size);\n  if (p) {\n    /* zero the memory */\n    os_memset(p, 0, count * size);\n  }\n  return p;\n}\n\n#endif /* !MEM_LIBC_MALLOC */\n"
  },
  {
    "path": "app/lwip/core/memp.c",
    "content": "/**\n * @file\n * Dynamic pool memory manager\n *\n * lwIP has dedicated pools for many structures (netconn, protocol control blocks,\n * packet buffers, ...). All these pools are managed here.\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/memp.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/raw.h\"\n#include \"lwip/tcp_impl.h\"\n#include \"lwip/igmp.h\"\n#include \"lwip/api.h\"\n#include \"lwip/api_msg.h\"\n#include \"lwip/tcpip.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/timers.h\"\n#include \"lwip/stats.h\"\n#include \"netif/etharp.h\"\n#include \"lwip/ip_frag.h\"\n#include \"lwip/snmp_structs.h\"\n#include \"lwip/snmp_msg.h\"\n#include \"lwip/dns.h\"\n#include \"netif/ppp_oe.h\"\n\n#include <string.h>\n\n#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */\n\nstruct memp {\n  struct memp *next;\n#if MEMP_OVERFLOW_CHECK\n  const char *file;\n  int line;\n#endif /* MEMP_OVERFLOW_CHECK */\n};\n\n#if MEMP_OVERFLOW_CHECK\n/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning\n * and at the end of each element, initialize them as 0xcd and check\n * them later. */\n/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,\n * every single element in each pool is checked!\n * This is VERY SLOW but also very helpful. */\n/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in\n * lwipopts.h to change the amount reserved for checking. */\n#ifndef MEMP_SANITY_REGION_BEFORE\n#define MEMP_SANITY_REGION_BEFORE  16\n#endif /* MEMP_SANITY_REGION_BEFORE*/\n#if MEMP_SANITY_REGION_BEFORE > 0\n#define MEMP_SANITY_REGION_BEFORE_ALIGNED    LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)\n#else\n#define MEMP_SANITY_REGION_BEFORE_ALIGNED    0\n#endif /* MEMP_SANITY_REGION_BEFORE*/\n#ifndef MEMP_SANITY_REGION_AFTER\n#define MEMP_SANITY_REGION_AFTER   16\n#endif /* MEMP_SANITY_REGION_AFTER*/\n#if MEMP_SANITY_REGION_AFTER > 0\n#define MEMP_SANITY_REGION_AFTER_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)\n#else\n#define MEMP_SANITY_REGION_AFTER_ALIGNED     0\n#endif /* MEMP_SANITY_REGION_AFTER*/\n\n/* MEMP_SIZE: save space for struct memp and for sanity check */\n#define MEMP_SIZE          (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)\n#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)\n\n#else /* MEMP_OVERFLOW_CHECK */\n\n/* No sanity checks\n * We don't need to preserve the struct memp while not allocated, so we\n * can save a little space and set MEMP_SIZE to 0.\n */\n#define MEMP_SIZE           0\n#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))\n\n#endif /* MEMP_OVERFLOW_CHECK */\n\n/** This array holds the first free element of each pool.\n *  Elements form a linked list. */\nstatic struct memp *memp_tab[MEMP_MAX];\n\n#else /* MEMP_MEM_MALLOC */\n\n#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))\n\n#endif /* MEMP_MEM_MALLOC */\n\n/** This array holds the element sizes of each pool. */\n#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC\nstatic\n#endif\nconst u32_t memp_sizes[MEMP_MAX] ICACHE_RODATA_ATTR = { //LWIP_MEM_ALIGN_SIZE\n#define LWIP_MEMPOOL(name,num,size,desc,attr)  LWIP_MEM_ALIGN_SIZE(size),\n#include \"lwip/memp_std.h\"\n};\n\nu16_t memp_sizes_test[1] = {PBUF_POOL_BUFSIZE,};\n\n#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */\n\n/** This array holds the number of elements in each pool. */\nstatic const u16_t memp_num[MEMP_MAX] = {\n#define LWIP_MEMPOOL(name,num,size,desc,attr)  (num),\n#include \"lwip/memp_std.h\"\n};\n\n/** This array holds a textual description of each pool. */\n//#ifdef LWIP_DEBUG\n//static const char *memp_desc[MEMP_MAX] = {\nconst char *memp_desc[MEMP_MAX] = {\n#define LWIP_MEMPOOL(name,num,size,desc,attr)  (desc),\n#include \"lwip/memp_std.h\"\n};\n//#endif /* LWIP_DEBUG */\n\n#if MEMP_SEPARATE_POOLS\n\n/** This creates each memory pool. These are named memp_memory_XXX_base (where\n * XXX is the name of the pool defined in memp_std.h).\n * To relocate a pool, declare it as extern in cc.h. Example for GCC:\n *   extern u8_t __attribute__((section(\".onchip_mem\"))) memp_memory_UDP_PCB_base[];\n */\n#define LWIP_MEMPOOL(name,num,size,desc,attr) u8_t memp_memory_ ## name ## _base \\\n  [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))] attr;   \n#include \"lwip/memp_std.h\"\n\n/** This array holds the base of each memory pool. */\nstatic u8_t *const memp_bases[] = { \n#define LWIP_MEMPOOL(name,num,size,desc,attr) memp_memory_ ## name ## _base,   \n#include \"lwip/memp_std.h\"\n};\n\n#else /* MEMP_SEPARATE_POOLS */\n\n/** This is the actual memory used by the pools (all pools in one big block). */\nstatic u8_t memp_memory[MEM_ALIGNMENT - 1 \n#define LWIP_MEMPOOL(name,num,size,desc, attr) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )\n#include \"lwip/memp_std.h\"\n];\n\n#endif /* MEMP_SEPARATE_POOLS */\n\n#if MEMP_SANITY_CHECK\n/**\n * Check that memp-lists don't form a circle, modify by ives at 2014.4.23.\n */\nstatic int ICACHE_FLASH_ATTR\nmemp_sanity(void)\n{\n  s16_t i;\n  struct memp *t, *h;\n\n  for (i = 0; i < MEMP_MAX; i++) {\n    t = memp_tab[i];\n    if(t != NULL) {\n      for (h = t->next; (t != NULL) && (h != NULL); t = t->next,\n        h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) {\n        if (t == h) {\n          return 0;\n        }\n      }\n    }\n  }\n  return 1;\n}\n#endif /* MEMP_SANITY_CHECK*/\n#if MEMP_OVERFLOW_CHECK\n#if defined(LWIP_DEBUG) && MEMP_STATS\nstatic const char * memp_overflow_names[] = {\n#define LWIP_MEMPOOL(name,num,size,desc,attr) \"/\"desc,\n#include \"lwip/memp_std.h\"\n  };\n#endif\n\n/**\n * Check if a memp element was victim of an overflow\n * (e.g. the restricted area after it has been altered)\n *\n * @param p the memp element to check\n * @param memp_type the pool p comes from\n */\nstatic void ICACHE_FLASH_ATTR\nmemp_overflow_check_element_overflow(struct memp *p, u16_t memp_type)\n{\n  u16_t k;\n  u8_t *m;\n#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0\n  m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type];\n  for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {\n    if (m[k] != 0xcd) {\n      char errstr[128] = \"detected memp overflow in pool \";\n      char digit[] = \"0\";\n      if(memp_type >= 10) {\n        digit[0] = '0' + (memp_type/10);\n        strcat(errstr, digit);\n      }\n      digit[0] = '0' + (memp_type%10);\n      strcat(errstr, digit);\n#if defined(LWIP_DEBUG) && MEMP_STATS\n      strcat(errstr, memp_overflow_names[memp_type]);\n#endif\n      LWIP_ASSERT(errstr, 0);\n    }\n  }\n#endif\n}\n\n/**\n * Check if a memp element was victim of an underflow\n * (e.g. the restricted area before it has been altered)\n *\n * @param p the memp element to check\n * @param memp_type the pool p comes from\n */\nstatic void ICACHE_FLASH_ATTR\nmemp_overflow_check_element_underflow(struct memp *p, u16_t memp_type)\n{\n  u16_t k;\n  u8_t *m;\n#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0\n  m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;\n  for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {\n    if (m[k] != 0xcd) {\n      char errstr[128] = \"detected memp underflow in pool \";\n      char digit[] = \"0\";\n      if(memp_type >= 10) {\n        digit[0] = '0' + (memp_type/10);\n        strcat(errstr, digit);\n      }\n      digit[0] = '0' + (memp_type%10);\n      strcat(errstr, digit);\n#if defined(LWIP_DEBUG) && MEMP_STATS\n      strcat(errstr, memp_overflow_names[memp_type]);\n#endif\n      LWIP_ASSERT(errstr, 0);\n    }\n  }\n#endif\n}\n\n/**\n * Do an overflow check for all elements in every pool.\n *\n * @see memp_overflow_check_element for a description of the check\n */\nstatic void ICACHE_FLASH_ATTR\nmemp_overflow_check_all(void)\n{\n  u16_t i, j;\n  struct memp *p;\n\n  p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);\n  for (i = 0; i < MEMP_MAX; ++i) {\n    p = p;\n    for (j = 0; j < memp_num[i]; ++j) {\n      memp_overflow_check_element_overflow(p, i);\n      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);\n    }\n  }\n  p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);\n  for (i = 0; i < MEMP_MAX; ++i) {\n    p = p;\n    for (j = 0; j < memp_num[i]; ++j) {\n      memp_overflow_check_element_underflow(p, i);\n      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);\n    }\n  }\n}\n\n/**\n * Initialize the restricted areas of all memp elements in every pool.\n */\nstatic void ICACHE_FLASH_ATTR\nmemp_overflow_init(void)\n{\n  u16_t i, j;\n  struct memp *p;\n  u8_t *m;\n\n  p = (struct memp *)LWIP_MEM_ALIGN(memp_memory);\n  for (i = 0; i < MEMP_MAX; ++i) {\n    p = p;\n    for (j = 0; j < memp_num[i]; ++j) {\n#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0\n      m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;\n      os_memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);\n#endif\n#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0\n      m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];\n      os_memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);\n#endif\n      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);\n    }\n  }\n}\n#endif /* MEMP_OVERFLOW_CHECK */\n\n/**\n * Initialize this module.\n * \n * Carves out memp_memory into linked lists for each pool-type.\n */\nvoid\nmemp_init(void)\n{\n  struct memp *memp;\n  u16_t i, j;\n\n  for (i = 0; i < MEMP_MAX; ++i) {\n    MEMP_STATS_AVAIL(used, i, 0);\n    MEMP_STATS_AVAIL(max, i, 0);\n    MEMP_STATS_AVAIL(err, i, 0);\n    MEMP_STATS_AVAIL(avail, i, memp_num[i]);\n  }\n\n#if !MEMP_SEPARATE_POOLS\n  memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);\n#endif /* !MEMP_SEPARATE_POOLS */\n  /* for every pool: */\n  for (i = 0; i < MEMP_MAX; ++i) {\n    memp_tab[i] = NULL;\n#if MEMP_SEPARATE_POOLS\n    memp = (struct memp*)memp_bases[i];\n#endif /* MEMP_SEPARATE_POOLS */\n    /* create a linked list of memp elements */\n    for (j = 0; j < memp_num[i]; ++j) {\n      memp->next = (struct memp *)memp_tab[i];\n      memp_tab[i] = memp;\n      memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]\n#if MEMP_OVERFLOW_CHECK\n        + MEMP_SANITY_REGION_AFTER_ALIGNED\n#endif\n      );\n    }\n  }\n#if MEMP_OVERFLOW_CHECK\n  memp_overflow_init();\n  /* check everything a first time to see if it worked */\n  memp_overflow_check_all();\n#endif /* MEMP_OVERFLOW_CHECK */\n}\n\n/**\n * Get an element from a specific pool.\n *\n * @param type the pool to get an element from\n *\n * the debug version has two more parameters:\n * @param file file name calling this function\n * @param line number of line where this function is called\n *\n * @return a pointer to the allocated memory or a NULL pointer on error\n */\nvoid *\n#if !MEMP_OVERFLOW_CHECK\nmemp_malloc(memp_t type)\n#else\nmemp_malloc_fn(memp_t type, const char* file, const int line)\n#endif\n{\n  struct memp *memp;\n  SYS_ARCH_DECL_PROTECT(old_level);\n \n  LWIP_ERROR(\"memp_malloc: type < MEMP_MAX\", (type < MEMP_MAX), return NULL;);\n\n  SYS_ARCH_PROTECT(old_level);\n#if MEMP_OVERFLOW_CHECK >= 2\n  memp_overflow_check_all();\n#endif /* MEMP_OVERFLOW_CHECK >= 2 */\n\n  memp = memp_tab[type];\n  \n  if (memp != NULL) {\n    memp_tab[type] = memp->next;\n#if MEMP_OVERFLOW_CHECK\n    memp->next = NULL;\n    memp->file = file;\n    memp->line = line;\n#endif /* MEMP_OVERFLOW_CHECK */\n    MEMP_STATS_INC_USED(used, type);\n    LWIP_ASSERT(\"memp_malloc: memp properly aligned\",\n                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);\n    memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);\n  } else {\n    LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"memp_malloc: out of memory in pool %s\\n\", memp_desc[type]));\n    MEMP_STATS_INC(err, type);\n  }\n\n  SYS_ARCH_UNPROTECT(old_level);\n\n  return memp;\n}\n\n/**\n * Put an element back into its pool.\n *\n * @param type the pool where to put mem\n * @param mem the memp element to free\n */\nvoid\nmemp_free(memp_t type, void *mem)\n{\n  struct memp *memp;\n  SYS_ARCH_DECL_PROTECT(old_level);\n\n  if (mem == NULL) {\n    return;\n  }\n  LWIP_ASSERT(\"memp_free: mem properly aligned\",\n                ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);\n\n  memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);\n\n  SYS_ARCH_PROTECT(old_level);\n#if MEMP_OVERFLOW_CHECK\n#if MEMP_OVERFLOW_CHECK >= 2\n  memp_overflow_check_all();\n#else\n  memp_overflow_check_element_overflow(memp, type);\n  memp_overflow_check_element_underflow(memp, type);\n#endif /* MEMP_OVERFLOW_CHECK >= 2 */\n#endif /* MEMP_OVERFLOW_CHECK */\n\n  MEMP_STATS_DEC(used, type); \n  \n  memp->next = memp_tab[type]; \n  memp_tab[type] = memp;\n\n#if MEMP_SANITY_CHECK\n  LWIP_ASSERT(\"memp sanity\", memp_sanity());\n#endif /* MEMP_SANITY_CHECK */\n\n  SYS_ARCH_UNPROTECT(old_level);\n}\n\n#endif /* MEMP_MEM_MALLOC */\n#if 0\nvoid memp_dump(void)\n{\n\t  printf(\"sizeof raw_pcb %u, memp_s1 %u, %s\\n\", sizeof(struct raw_pcb), memp_sizes[0], memp_desc[0]);\n\t  printf(\"sizeof udp_pcb %u, memp_s2 %u, %s\\n\", sizeof(struct udp_pcb), memp_sizes[1], memp_desc[1]);\n\t  printf(\"sizeof tcp_pcb %u, memp_s3 %u, %s\\n\", sizeof(struct tcp_pcb), memp_sizes[2], memp_desc[2]);\n\t  printf(\"sizeof tcp_pcb_listen %u, memp_s4 %u, %s\\n\", sizeof(struct tcp_pcb_listen), memp_sizes[3], memp_desc[3]);\n\t  printf(\"sizeof tcp_seg %u, memp_s5 %u, %s\\n\", sizeof(struct tcp_seg), memp_sizes[4], memp_desc[4]);\n\t  printf(\"sizeof sys_timeo %u, memp_s6 %u, %s\\n\", sizeof(struct sys_timeo), memp_sizes[5], memp_desc[5]);\n\t  printf(\"sizeof pbuf %u, memp_s7 %u, %s\\n\", sizeof(struct pbuf), memp_sizes[6], memp_desc[6]);\n\t  printf(\"align pbuf size %u, memp_s8 %u, %s\\n\", (PBUF_POOL_BUFSIZE), memp_sizes[7], memp_desc[7]);\n\t  printf(\"TCP_MSS %d PBUF_LINK_HLEN %d ETH_PAD_SIZE %d\\n\", TCP_MSS, PBUF_LINK_HLEN, ETH_PAD_SIZE);\n\t  printf(\"TCP_MSS + PBUF_LINK_HLEN + ETH_PAD_SIZE %d \\n\", TCP_MSS+PBUF_LINK_HLEN+ETH_PAD_SIZE+40);\n\t  printf(\"test size %u\\n\",memp_sizes_test[0]);\n\t  printf(\"sizeof memp_memory_PBUF_pool %u \\n\", sizeof(memp_memory_PBUF_POOL_base));\n}\n#endif //0000\n"
  },
  {
    "path": "app/lwip/core/netif.c",
    "content": "/**\n * @file\n * lwIP network interface abstraction\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/def.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/tcp_impl.h\"\n#include \"lwip/snmp.h\"\n#include \"lwip/igmp.h\"\n#include \"netif/etharp.h\"\n#include \"lwip/stats.h\"\n#if ENABLE_LOOPBACK\n#include \"lwip/sys.h\"\n#if LWIP_NETIF_LOOPBACK_MULTITHREADING\n#include \"lwip/tcpip.h\"\n#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */\n#endif /* ENABLE_LOOPBACK */\n\n#if LWIP_AUTOIP\n#include \"lwip/autoip.h\"\n#endif /* LWIP_AUTOIP */\n#if LWIP_DHCP\n#include \"lwip/dhcp.h\"\n#endif /* LWIP_DHCP */\n\n#if LWIP_NETIF_STATUS_CALLBACK\n#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)\n#else\n#define NETIF_STATUS_CALLBACK(n)\n#endif /* LWIP_NETIF_STATUS_CALLBACK */ \n\n#if LWIP_NETIF_LINK_CALLBACK\n#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0)\n#else\n#define NETIF_LINK_CALLBACK(n)\n#endif /* LWIP_NETIF_LINK_CALLBACK */ \n\nstruct netif *netif_list;\nstruct netif *netif_default;\n\n#if LWIP_HAVE_LOOPIF\nstatic struct netif loop_netif;\n\n/**\n * Initialize a lwip network interface structure for a loopback interface\n *\n * @param netif the lwip network interface structure for this loopif\n * @return ERR_OK if the loopif is initialized\n *         ERR_MEM if private data couldn't be allocated\n */\n static err_t ICACHE_FLASH_ATTR\nnetif_loopif_init(struct netif *netif)\n{\n  /* initialize the snmp variables and counters inside the struct netif\n   * ifSpeed: no assumption can be made!\n   */\n  NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);\n\n  netif->name[0] = 'l';\n  netif->name[1] = 'o';\n  netif->output = netif_loop_output;\n  return ERR_OK;\n}\n#endif /* LWIP_HAVE_LOOPIF */\n\nvoid\nnetif_init(void)\n{\n#if LWIP_HAVE_LOOPIF\n  ip_addr_t loop_ipaddr, loop_netmask, loop_gw;\n  IP4_ADDR(&loop_gw, 127,0,0,1);\n  IP4_ADDR(&loop_ipaddr, 127,0,0,1);\n  IP4_ADDR(&loop_netmask, 255,0,0,0);\n\n#if NO_SYS\n  netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input);\n#else  /* NO_SYS */\n  netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input);\n#endif /* NO_SYS */\n  netif_set_up(&loop_netif);\n\n#endif /* LWIP_HAVE_LOOPIF */\n}\n\n/**\n * Add a network interface to the list of lwIP netifs.\n *\n * @param netif a pre-allocated netif structure\n * @param ipaddr IP address for the new netif\n * @param netmask network mask for the new netif\n * @param gw default gateway IP address for the new netif\n * @param state opaque data passed to the new netif\n * @param init callback function that initializes the interface\n * @param input callback function that is called to pass\n * ingress packets up in the protocol layer stack.\n *\n * @return netif, or NULL if failed.\n */\nstruct netif *\nnetif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,\n  ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)\n{\n  static u8_t netifnum = 0;\n\n  LWIP_ASSERT(\"No init function given\", init != NULL);\n\n  /* reset new interface configuration state */\n  ip_addr_set_zero(&netif->ip_addr);\n  ip_addr_set_zero(&netif->netmask);\n  ip_addr_set_zero(&netif->gw);\n  netif->flags = 0;\n#if LWIP_DHCP\n  /* netif not under DHCP control by default */\n  netif->dhcp = NULL;\n  netif->dhcps_pcb = NULL;\n#endif /* LWIP_DHCP */\n#if LWIP_AUTOIP\n  /* netif not under AutoIP control by default */\n  netif->autoip = NULL;\n#endif /* LWIP_AUTOIP */\n#if LWIP_NETIF_STATUS_CALLBACK\n  netif->status_callback = NULL;\n#endif /* LWIP_NETIF_STATUS_CALLBACK */\n#if LWIP_NETIF_LINK_CALLBACK\n  netif->link_callback = NULL;\n#endif /* LWIP_NETIF_LINK_CALLBACK */\n#if LWIP_IGMP\n  netif->igmp_mac_filter = NULL;\n#endif /* LWIP_IGMP */\n#if ENABLE_LOOPBACK\n  netif->loop_first = NULL;\n  netif->loop_last = NULL;\n#endif /* ENABLE_LOOPBACK */\n\n  /* remember netif specific state information data */\n  netif->state = state;\n  netif->num = netifnum++;\n  netif->input = input;\n#if LWIP_NETIF_HWADDRHINT\n  netif->addr_hint = NULL;\n#endif /* LWIP_NETIF_HWADDRHINT*/\n#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS\n  netif->loop_cnt_current = 0;\n#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */\n\n  netif_set_addr(netif, ipaddr, netmask, gw);\n\n  /* call user specified initialization function for netif */\n  if (init(netif) != ERR_OK) {\n    return NULL;\n  }\n\n  /* add this netif to the list */\n  netif->next = netif_list;\n  netif_list = netif;\n  snmp_inc_iflist();\n\n#if LWIP_IGMP\n  /* start IGMP processing */\n  if (netif->flags & NETIF_FLAG_IGMP) {\n    igmp_start(netif);\n  }\n#endif /* LWIP_IGMP */\n\n  LWIP_DEBUGF(NETIF_DEBUG, (\"netif: added interface %c%c IP addr \",\n    netif->name[0], netif->name[1]));\n  ip_addr_debug_print(NETIF_DEBUG, ipaddr);\n  LWIP_DEBUGF(NETIF_DEBUG, (\" netmask \"));\n  ip_addr_debug_print(NETIF_DEBUG, netmask);\n  LWIP_DEBUGF(NETIF_DEBUG, (\" gw \"));\n  ip_addr_debug_print(NETIF_DEBUG, gw);\n  LWIP_DEBUGF(NETIF_DEBUG, (\"\\n\"));\n  return netif;\n}\n\n/**\n * Change IP address configuration for a network interface (including netmask\n * and default gateway).\n *\n * @param netif the network interface to change\n * @param ipaddr the new IP address\n * @param netmask the new netmask\n * @param gw the new default gateway\n */\nvoid\nnetif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,\n    ip_addr_t *gw)\n{\n  netif_set_ipaddr(netif, ipaddr);\n  netif_set_netmask(netif, netmask);\n  netif_set_gw(netif, gw);\n}\n\n/**\n * Remove a network interface from the list of lwIP netifs.\n *\n * @param netif the network interface to remove\n */\nvoid\nnetif_remove(struct netif *netif)\n{\n  if (netif == NULL) {\n    return;\n  }\n\n#if LWIP_IGMP\n  /* stop IGMP processing */\n  if (netif->flags & NETIF_FLAG_IGMP) {\n    igmp_stop(netif);\n  }\n#endif /* LWIP_IGMP */\n  if (netif_is_up(netif)) {\n    /* set netif down before removing (call callback function) */\n    netif_set_down(netif);\n  }\n\n  snmp_delete_ipaddridx_tree(netif);\n\n  /*  is it the first netif? */\n  if (netif_list == netif) {\n    netif_list = netif->next;\n  } else {\n    /*  look for netif further down the list */\n    struct netif * tmpNetif;\n    for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {\n      if (tmpNetif->next == netif) {\n        tmpNetif->next = netif->next;\n        break;\n      }\n    }\n    if (tmpNetif == NULL)\n      return; /*  we didn't find any netif today */\n  }\n  snmp_dec_iflist();\n  /* this netif is default? */\n  if (netif_default == netif) {\n    /* reset default netif */\n    netif_set_default(NULL);\n  }\n  LWIP_DEBUGF( NETIF_DEBUG, (\"netif_remove: removed netif\\n\") );\n}\n\n/**\n * Find a network interface by searching for its name\n *\n * @param name the name of the netif (like netif->name) plus concatenated number\n * in ascii representation (e.g. 'en0')\n */\nstruct netif *\nnetif_find(char *name)\n{\n  struct netif *netif;\n  u8_t num;\n\n  if (name == NULL) {\n    return NULL;\n  }\n\n  num = name[2] - '0';\n\n  for(netif = netif_list; netif != NULL; netif = netif->next) {\n    if (num == netif->num &&\n       name[0] == netif->name[0] &&\n       name[1] == netif->name[1]) {\n      LWIP_DEBUGF(NETIF_DEBUG, (\"netif_find: found %c%c\\n\", name[0], name[1]));\n      return netif;\n    }\n  }\n  LWIP_DEBUGF(NETIF_DEBUG, (\"netif_find: didn't find %c%c\\n\", name[0], name[1]));\n  return NULL;\n}\n\n/**\n * Change the IP address of a network interface\n *\n * @param netif the network interface to change\n * @param ipaddr the new IP address\n *\n * @note call netif_set_addr() if you also want to change netmask and\n * default gateway\n */\nvoid\nnetif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)\n{\n  /* TODO: Handling of obsolete pcbs */\n  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */\n#if LWIP_TCP\n  struct tcp_pcb *pcb;\n  struct tcp_pcb_listen *lpcb;\n\n  /* address is actually being changed? */\n  if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {\n    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */\n    LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, (\"netif_set_ipaddr: netif address being changed\\n\"));\n    pcb = tcp_active_pcbs;\n    while (pcb != NULL) {\n      /* PCB bound to current local interface address? */\n      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))\n#if LWIP_AUTOIP\n        /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */\n        && !ip_addr_islinklocal(&(pcb->local_ip))\n#endif /* LWIP_AUTOIP */\n        ) {\n        /* this connection must be aborted */\n        struct tcp_pcb *next = pcb->next;\n        LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, (\"netif_set_ipaddr: aborting TCP pcb %p\\n\", (void *)pcb));\n        tcp_abort(pcb);\n        pcb = next;\n      } else {\n        pcb = pcb->next;\n      }\n    }\n    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {\n      /* PCB bound to current local interface address? */\n      if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&\n          (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {\n        /* The PCB is listening to the old ipaddr and\n         * is set to listen to the new one instead */\n        ip_addr_set(&(lpcb->local_ip), ipaddr);\n      }\n    }\n  }\n#endif\n  snmp_delete_ipaddridx_tree(netif);\n  snmp_delete_iprteidx_tree(0,netif);\n  /* set new IP address to netif */\n  ip_addr_set(&(netif->ip_addr), ipaddr);\n  snmp_insert_ipaddridx_tree(netif);\n  snmp_insert_iprteidx_tree(0,netif);\n\n  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"netif: IP address of interface %c%c set to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n    netif->name[0], netif->name[1],\n    ip4_addr1_16(&netif->ip_addr),\n    ip4_addr2_16(&netif->ip_addr),\n    ip4_addr3_16(&netif->ip_addr),\n    ip4_addr4_16(&netif->ip_addr)));\n}\n\n/**\n * Change the default gateway for a network interface\n *\n * @param netif the network interface to change\n * @param gw the new default gateway\n *\n * @note call netif_set_addr() if you also want to change ip address and netmask\n */\nvoid\nnetif_set_gw(struct netif *netif, ip_addr_t *gw)\n{\n  ip_addr_set(&(netif->gw), gw);\n  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"netif: GW address of interface %c%c set to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n    netif->name[0], netif->name[1],\n    ip4_addr1_16(&netif->gw),\n    ip4_addr2_16(&netif->gw),\n    ip4_addr3_16(&netif->gw),\n    ip4_addr4_16(&netif->gw)));\n}\n\n/**\n * Change the netmask of a network interface\n *\n * @param netif the network interface to change\n * @param netmask the new netmask\n *\n * @note call netif_set_addr() if you also want to change ip address and\n * default gateway\n */\nvoid\nnetif_set_netmask(struct netif *netif, ip_addr_t *netmask)\n{\n  snmp_delete_iprteidx_tree(0, netif);\n  /* set new netmask to netif */\n  ip_addr_set(&(netif->netmask), netmask);\n  snmp_insert_iprteidx_tree(0, netif);\n  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (\"netif: netmask of interface %c%c set to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n    netif->name[0], netif->name[1],\n    ip4_addr1_16(&netif->netmask),\n    ip4_addr2_16(&netif->netmask),\n    ip4_addr3_16(&netif->netmask),\n    ip4_addr4_16(&netif->netmask)));\n}\n\n/**\n * Set a network interface as the default network interface\n * (used to output all packets for which no specific route is found)\n *\n * @param netif the default network interface\n */\nvoid\nnetif_set_default(struct netif *netif)\n{\n  if (netif == NULL) {\n    /* remove default route */\n    snmp_delete_iprteidx_tree(1, netif);\n  } else {\n    /* install default route */\n    snmp_insert_iprteidx_tree(1, netif);\n  }\n  netif_default = netif;\n  LWIP_DEBUGF(NETIF_DEBUG, (\"netif: setting default interface %c%c\\n\",\n           netif ? netif->name[0] : '\\'', netif ? netif->name[1] : '\\''));\n}\n\n/**\n * Bring an interface up, available for processing\n * traffic.\n * \n * @note: Enabling DHCP on a down interface will make it come\n * up once configured.\n * \n * @see dhcp_start()\n */ \nvoid netif_set_up(struct netif *netif)\n{\n  if (!(netif->flags & NETIF_FLAG_UP)) {\n    netif->flags |= NETIF_FLAG_UP;\n    \n#if LWIP_SNMP\n    snmp_get_sysuptime(&netif->ts);\n#endif /* LWIP_SNMP */\n\n    NETIF_STATUS_CALLBACK(netif);\n\n    if (netif->flags & NETIF_FLAG_LINK_UP) {\n#if LWIP_ARP\n      /* For Ethernet network interfaces, we would like to send a \"gratuitous ARP\" */ \n      if (netif->flags & (NETIF_FLAG_ETHARP)) {\n        etharp_gratuitous(netif);\n      }\n#endif /* LWIP_ARP */\n\n#if LWIP_IGMP\n      /* resend IGMP memberships */\n      if (netif->flags & NETIF_FLAG_IGMP) {\n        igmp_report_groups( netif);\n      }\n#endif /* LWIP_IGMP */\n    }\n  }\n}\n\n/**\n * Bring an interface down, disabling any traffic processing.\n *\n * @note: Enabling DHCP on a down interface will make it come\n * up once configured.\n * \n * @see dhcp_start()\n */ \nvoid netif_set_down(struct netif *netif)\n{\n  if (netif->flags & NETIF_FLAG_UP) {\n    netif->flags &= ~NETIF_FLAG_UP;\n#if LWIP_SNMP\n    snmp_get_sysuptime(&netif->ts);\n#endif\n\n#if LWIP_ARP\n    if (netif->flags & NETIF_FLAG_ETHARP) {\n      etharp_cleanup_netif(netif);\n    }\n#endif /* LWIP_ARP */\n    NETIF_STATUS_CALLBACK(netif);\n  }\n}\n\n#if LWIP_NETIF_STATUS_CALLBACK\n/**\n * Set callback to be called when interface is brought up/down\n */\nvoid netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback)\n{\n  if (netif) {\n    netif->status_callback = status_callback;\n  }\n}\n#endif /* LWIP_NETIF_STATUS_CALLBACK */\n\n/**\n * Called by a driver when its link goes up\n */\nvoid netif_set_link_up(struct netif *netif )\n{\n  if (!(netif->flags & NETIF_FLAG_LINK_UP)) {\n    netif->flags |= NETIF_FLAG_LINK_UP;\n\n#if LWIP_DHCP\n    if (netif->dhcp) {\n      dhcp_network_changed(netif);\n    }\n#endif /* LWIP_DHCP */\n\n#if LWIP_AUTOIP\n    if (netif->autoip) {\n      autoip_network_changed(netif);\n    }\n#endif /* LWIP_AUTOIP */\n\n    if (netif->flags & NETIF_FLAG_UP) {\n#if LWIP_ARP\n      /* For Ethernet network interfaces, we would like to send a \"gratuitous ARP\" */ \n      if (netif->flags & NETIF_FLAG_ETHARP) {\n        etharp_gratuitous(netif);\n      }\n#endif /* LWIP_ARP */\n\n#if LWIP_IGMP\n      /* resend IGMP memberships */\n      if (netif->flags & NETIF_FLAG_IGMP) {\n        igmp_report_groups( netif);\n      }\n#endif /* LWIP_IGMP */\n    }\n    NETIF_LINK_CALLBACK(netif);\n  }\n}\n\n/**\n * Called by a driver when its link goes down\n */\nvoid netif_set_link_down(struct netif *netif )\n{\n  if (netif->flags & NETIF_FLAG_LINK_UP) {\n    netif->flags &= ~NETIF_FLAG_LINK_UP;\n    NETIF_LINK_CALLBACK(netif);\n  }\n}\n\n#if LWIP_NETIF_LINK_CALLBACK\n/**\n * Set callback to be called when link is brought up/down\n */\nvoid netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback)\n{\n  if (netif) {\n    netif->link_callback = link_callback;\n  }\n}\n#endif /* LWIP_NETIF_LINK_CALLBACK */\n\n#if ENABLE_LOOPBACK\n/**\n * Send an IP packet to be received on the same netif (loopif-like).\n * The pbuf is simply copied and handed back to netif->input.\n * In multithreaded mode, this is done directly since netif->input must put\n * the packet on a queue.\n * In callback mode, the packet is put on an internal queue and is fed to\n * netif->input by netif_poll().\n *\n * @param netif the lwip network interface structure\n * @param p the (IP) packet to 'send'\n * @param ipaddr the ip address to send the packet to (not used)\n * @return ERR_OK if the packet has been sent\n *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated\n */\nerr_t\nnetif_loop_output(struct netif *netif, struct pbuf *p,\n       ip_addr_t *ipaddr)\n{\n  struct pbuf *r;\n  err_t err;\n  struct pbuf *last;\n#if LWIP_LOOPBACK_MAX_PBUFS\n  u8_t clen = 0;\n#endif /* LWIP_LOOPBACK_MAX_PBUFS */\n  /* If we have a loopif, SNMP counters are adjusted for it,\n   * if not they are adjusted for 'netif'. */\n#if LWIP_SNMP\n#if LWIP_HAVE_LOOPIF\n  struct netif *stats_if = &loop_netif;\n#else /* LWIP_HAVE_LOOPIF */\n  struct netif *stats_if = netif;\n#endif /* LWIP_HAVE_LOOPIF */\n#endif /* LWIP_SNMP */\n  SYS_ARCH_DECL_PROTECT(lev);\n  LWIP_UNUSED_ARG(ipaddr);\n\n  /* Allocate a new pbuf */\n  r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);\n  if (r == NULL) {\n    LINK_STATS_INC(link.memerr);\n    LINK_STATS_INC(link.drop);\n    snmp_inc_ifoutdiscards(stats_if);\n    return ERR_MEM;\n  }\n#if LWIP_LOOPBACK_MAX_PBUFS\n  clen = pbuf_clen(r);\n  /* check for overflow or too many pbuf on queue */\n  if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||\n     ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {\n    pbuf_free(r);\n    LINK_STATS_INC(link.memerr);\n    LINK_STATS_INC(link.drop);\n    snmp_inc_ifoutdiscards(stats_if);\n    return ERR_MEM;\n  }\n  netif->loop_cnt_current += clen;\n#endif /* LWIP_LOOPBACK_MAX_PBUFS */\n\n  /* Copy the whole pbuf queue p into the single pbuf r */\n  if ((err = pbuf_copy(r, p)) != ERR_OK) {\n    pbuf_free(r);\n    LINK_STATS_INC(link.memerr);\n    LINK_STATS_INC(link.drop);\n    snmp_inc_ifoutdiscards(stats_if);\n    return err;\n  }\n\n  /* Put the packet on a linked list which gets emptied through calling\n     netif_poll(). */\n\n  /* let last point to the last pbuf in chain r */\n  for (last = r; last->next != NULL; last = last->next);\n\n  SYS_ARCH_PROTECT(lev);\n  if(netif->loop_first != NULL) {\n    LWIP_ASSERT(\"if first != NULL, last must also be != NULL\", netif->loop_last != NULL);\n    netif->loop_last->next = r;\n    netif->loop_last = last;\n  } else {\n    netif->loop_first = r;\n    netif->loop_last = last;\n  }\n  SYS_ARCH_UNPROTECT(lev);\n\n  LINK_STATS_INC(link.xmit);\n  snmp_add_ifoutoctets(stats_if, p->tot_len);\n  snmp_inc_ifoutucastpkts(stats_if);\n\n#if LWIP_NETIF_LOOPBACK_MULTITHREADING\n  /* For multithreading environment, schedule a call to netif_poll */\n  tcpip_callback((tcpip_callback_fn)netif_poll, netif);\n#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */\n\n  return ERR_OK;\n}\n\n/**\n * Call netif_poll() in the main loop of your application. This is to prevent\n * reentering non-reentrant functions like tcp_input(). Packets passed to\n * netif_loop_output() are put on a list that is passed to netif->input() by\n * netif_poll().\n */\nvoid\nnetif_poll(struct netif *netif)\n{\n  struct pbuf *in;\n  /* If we have a loopif, SNMP counters are adjusted for it,\n   * if not they are adjusted for 'netif'. */\n#if LWIP_SNMP\n#if LWIP_HAVE_LOOPIF\n  struct netif *stats_if = &loop_netif;\n#else /* LWIP_HAVE_LOOPIF */\n  struct netif *stats_if = netif;\n#endif /* LWIP_HAVE_LOOPIF */\n#endif /* LWIP_SNMP */\n  SYS_ARCH_DECL_PROTECT(lev);\n\n  do {\n    /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */\n    SYS_ARCH_PROTECT(lev);\n    in = netif->loop_first;\n    if (in != NULL) {\n      struct pbuf *in_end = in;\n#if LWIP_LOOPBACK_MAX_PBUFS\n      u8_t clen = pbuf_clen(in);\n      /* adjust the number of pbufs on queue */\n      LWIP_ASSERT(\"netif->loop_cnt_current underflow\",\n        ((netif->loop_cnt_current - clen) < netif->loop_cnt_current));\n      netif->loop_cnt_current -= clen;\n#endif /* LWIP_LOOPBACK_MAX_PBUFS */\n      while (in_end->len != in_end->tot_len) {\n        LWIP_ASSERT(\"bogus pbuf: len != tot_len but next == NULL!\", in_end->next != NULL);\n        in_end = in_end->next;\n      }\n      /* 'in_end' now points to the last pbuf from 'in' */\n      if (in_end == netif->loop_last) {\n        /* this was the last pbuf in the list */\n        netif->loop_first = netif->loop_last = NULL;\n      } else {\n        /* pop the pbuf off the list */\n        netif->loop_first = in_end->next;\n        LWIP_ASSERT(\"should not be null since first != last!\", netif->loop_first != NULL);\n      }\n      /* De-queue the pbuf from its successors on the 'loop_' list. */\n      in_end->next = NULL;\n    }\n    SYS_ARCH_UNPROTECT(lev);\n\n    if (in != NULL) {\n      LINK_STATS_INC(link.recv);\n      snmp_add_ifinoctets(stats_if, in->tot_len);\n      snmp_inc_ifinucastpkts(stats_if);\n      /* loopback packets are always IP packets! */\n      if (ip_input(in, netif) != ERR_OK) {\n        pbuf_free(in);\n      }\n      /* Don't reference the packet any more! */\n      in = NULL;\n    }\n  /* go on while there is a packet on the list */\n  } while (netif->loop_first != NULL);\n}\n\n#if !LWIP_NETIF_LOOPBACK_MULTITHREADING\n/**\n * Calls netif_poll() for every netif on the netif_list.\n */\nvoid\nnetif_poll_all(void)\n{\n  struct netif *netif = netif_list;\n  /* loop through netifs */\n  while (netif != NULL) {\n    netif_poll(netif);\n    /* proceed to next network interface */\n    netif = netif->next;\n  }\n}\n#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */\n#endif /* ENABLE_LOOPBACK */\n"
  },
  {
    "path": "app/lwip/core/pbuf.c",
    "content": "/**\n * @file\n * Packet buffer management\n *\n * Packets are built from the pbuf data structure. It supports dynamic\n * memory allocation for packet contents or can reference externally\n * managed packet contents both in RAM and ROM. Quick allocation for\n * incoming packets is provided through pools with fixed sized pbufs.\n *\n * A packet may span over multiple pbufs, chained as a singly linked\n * list. This is called a \"pbuf chain\".\n *\n * Multiple packets may be queued, also using this singly linked list.\n * This is called a \"packet queue\".\n * \n * So, a packet queue consists of one or more pbuf chains, each of\n * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE\n * NOT SUPPORTED!!! Use helper structs to queue multiple packets.\n * \n * The differences between a pbuf chain and a packet queue are very\n * precise but subtle. \n *\n * The last pbuf of a packet has a ->tot_len field that equals the\n * ->len field. It can be found by traversing the list. If the last\n * pbuf of a packet has a ->next field other than NULL, more packets\n * are on the queue.\n *\n * Therefore, looping through a pbuf of a single packet, has an\n * loop end condition (tot_len == p->len), NOT (next == NULL).\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/stats.h\"\n#include \"lwip/def.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/pbuf.h\"\n#include \"lwip/sys.h\"\n#include \"arch/perf.h\"\n#if TCP_QUEUE_OOSEQ\n#include \"lwip/tcp_impl.h\"\n#endif\n#if LWIP_CHECKSUM_ON_COPY\n#include \"lwip/inet_chksum.h\"\n#endif\n\n#include <string.h>\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n#ifdef EBUF_LWIP\n#define EP_OFFSET 36\n#else\n#define EP_OFFSET 0\n#endif /* ESF_LWIP */\n\n#define SIZEOF_STRUCT_PBUF        LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))\n/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically\n   aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */\n#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)\n\n/**\n * Attempt to reclaim some memory from queued out-of-sequence TCP segments\n * if we run out of pool pbufs. It's better to give priority to new packets\n * if we're running out.\n */\n#if TCP_QUEUE_OOSEQ\nvoid ICACHE_FLASH_ATTR\npbuf_free_ooseq_new(void* arg)\n{\n  struct tcp_pcb* pcb;\n  struct tcp_seg *head = NULL;\n  struct tcp_seg *seg1 = NULL;\n  struct tcp_seg *seg2 = NULL;\n  for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {\n\t  head = pcb->ooseq;\n\t  seg1 = head;\n\t  if (head != NULL) {\n\t\t  if (seg1->next == NULL){\n\t\t\t  head = head->next;\n\t\t\t  tcp_seg_free(seg1);\n\t\t\t  pcb->ooseq = head;\n\t\t  } else {\n\t\t\t  while (seg1 != NULL){\n\t\t\t\t  seg2 = seg1;\n\t\t\t\t  seg2 = seg2->next;\n\t\t\t\t  if (seg2 ->next == NULL){\n\t\t\t\t\t  seg1->next = seg2->next;\n\t\t\t\t\t  tcp_seg_free(seg2);\n\t\t\t\t\t  break;\n\t\t\t\t  }\n\t\t\t\t  seg1 = seg1->next;\n\t\t\t  }\n\t\t\t  pcb->ooseq = head;\n\t\t  }\n\t  }\n  }\n}\n#endif\n\n#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS\n#define PBUF_POOL_IS_EMPTY()\n#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */\n/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */\n#ifndef PBUF_POOL_FREE_OOSEQ\n#define PBUF_POOL_FREE_OOSEQ 1\n#endif /* PBUF_POOL_FREE_OOSEQ */\n\n#if PBUF_POOL_FREE_OOSEQ\n#include \"lwip/tcpip.h\"\n#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()\nstatic u8_t pbuf_free_ooseq_queued;\n/**\n * Attempt to reclaim some memory from queued out-of-sequence TCP segments\n * if we run out of pool pbufs. It's better to give priority to new packets\n * if we're running out.\n *\n * This must be done in the correct thread context therefore this function\n * can only be used with NO_SYS=0 and through tcpip_callback.\n */\nstatic void ICACHE_FLASH_ATTR\npbuf_free_ooseq(void* arg)\n{\n  struct tcp_pcb* pcb;\n  SYS_ARCH_DECL_PROTECT(old_level);\n  LWIP_UNUSED_ARG(arg);\n\n  SYS_ARCH_PROTECT(old_level);\n  pbuf_free_ooseq_queued = 0;\n  SYS_ARCH_UNPROTECT(old_level);\n\n  for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {\n    if (NULL != pcb->ooseq) {\n      /** Free the ooseq pbufs of one PCB only */\n      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_free_ooseq: freeing out-of-sequence pbufs\\n\"));\n      tcp_segs_free(pcb->ooseq);\n      pcb->ooseq = NULL;\n      return;\n    }\n  }\n}\n\n/** Queue a call to pbuf_free_ooseq if not already queued. */\nstatic void ICACHE_FLASH_ATTR\npbuf_pool_is_empty(void)\n{\n  u8_t queued;\n  SYS_ARCH_DECL_PROTECT(old_level);\n\n  SYS_ARCH_PROTECT(old_level);\n  queued = pbuf_free_ooseq_queued;\n  pbuf_free_ooseq_queued = 1;\n  SYS_ARCH_UNPROTECT(old_level);\n\n  if(!queued) {\n    /* queue a call to pbuf_free_ooseq if not already queued */\n    if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {\n      SYS_ARCH_PROTECT(old_level);\n      pbuf_free_ooseq_queued = 0;\n      SYS_ARCH_UNPROTECT(old_level);\n    }\n  }\n}\n#endif /* PBUF_POOL_FREE_OOSEQ */\n#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */\n\n/**\n * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).\n *\n * The actual memory allocated for the pbuf is determined by the\n * layer at which the pbuf is allocated and the requested size\n * (from the size parameter).\n *\n * @param layer flag to define header size\n * @param length size of the pbuf's payload\n * @param type this parameter decides how and where the pbuf\n * should be allocated as follows:\n *\n * - PBUF_RAM: buffer memory for pbuf is allocated as one large\n *             chunk. This includes protocol headers as well.\n * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for\n *             protocol headers. Additional headers must be prepended\n *             by allocating another pbuf and chain in to the front of\n *             the ROM pbuf. It is assumed that the memory used is really\n *             similar to ROM in that it is immutable and will not be\n *             changed. Memory which is dynamic should generally not\n *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.\n * - PBUF_REF: no buffer memory is allocated for the pbuf, even for\n *             protocol headers. It is assumed that the pbuf is only\n *             being used in a single thread. If the pbuf gets queued,\n *             then pbuf_take should be called to copy the buffer.\n * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from\n *              the pbuf pool that is allocated during pbuf_init().\n *\n * @return the allocated pbuf. If multiple pbufs where allocated, this\n * is the first pbuf of a pbuf chain.\n */\nstruct pbuf *\npbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)\n{\n  struct pbuf *p, *q, *r;\n  u16_t offset;\n  s32_t rem_len; /* remaining length */\n  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_alloc(length=%\"U16_F\")\\n\", length));\n\n  /* determine header offset */\n  offset = 0;\n  switch (layer) {\n  case PBUF_TRANSPORT:\n    /* add room for transport (often TCP) layer header */\n    offset += PBUF_TRANSPORT_HLEN;\n    /* FALLTHROUGH */\n  case PBUF_IP:\n    /* add room for IP layer header */\n    offset += PBUF_IP_HLEN;\n    /* FALLTHROUGH */\n  case PBUF_LINK:\n    /* add room for link layer header */\n    offset += PBUF_LINK_HLEN;\n\n#ifdef PBUF_RSV_FOR_WLAN\n    /*\n     * 1. LINK_HLEN 14Byte will be remove in WLAN layer\n     * 2. IEEE80211_HDR_MAX_LEN needs 40 bytes.\n     * 3. encryption needs exra 4 bytes ahead of actual data payload, and require\n     *     DAddr and SAddr to be 4-byte aligned.\n     * 4. TRANSPORT and IP are all 20, 4 bytes aligned, nice...\n     * 5. LCC add 6 bytes more, We don't consider WAPI yet...\n     * 6. define LWIP_MEM_ALIGN to be 4 Byte aligned, pbuf struct is 16B, Only thing may be\n     *     matter is ether_hdr is not 4B aligned.\n     *\n     * So, we need extra (40 + 4 - 14) = 30 and it's happen to be 4-Byte aligned\n     *\n     *    1. lwip\n     *         | empty 30B    | eth_hdr (14B)  | payload ...|\n     *              total: 44B ahead payload\n     *    2. net80211\n     *         | max 80211 hdr, 32B | ccmp/tkip iv (8B) | sec rsv(4B) | payload ...|\n     *              total: 40B ahead sec_rsv and 44B ahead payload\n     *\n     */\n    offset += EP_OFFSET; //remove LINK hdr in wlan\n#endif /* PBUF_RSV_FOR_WLAN */\n\n    break;\n  case PBUF_RAW:\n#ifdef PBUF_RSV_FOR_WLAN\n      /*\n       *   RAW pbuf suppose\n       */\n    offset += EP_OFFSET; //remove LINK hdr in wlan\n#endif /* PBUF_RAW */\n    break;\n  default:\n    LWIP_ASSERT(\"pbuf_alloc: bad pbuf layer\", 0);\n    return NULL;\n  }\n\n  switch (type) {\n  case PBUF_POOL:\n    /* allocate head of pbuf chain into p */\n    p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);\n    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_alloc: allocated pbuf %p\\n\", (void *)p));\n    if (p == NULL) {\n      PBUF_POOL_IS_EMPTY();\n      return NULL;\n    }\n    p->type = type;\n    p->next = NULL;\n\n    /* make the payload pointer point 'offset' bytes into pbuf data memory */\n    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));\n    LWIP_ASSERT(\"pbuf_alloc: pbuf p->payload properly aligned\",\n            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);\n    /* the total length of the pbuf chain is the requested size */\n    p->tot_len = length;\n    /* set the length of the first pbuf in the chain */\n    p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));\n    LWIP_ASSERT(\"check p->payload + p->len does not overflow pbuf\",\n                ((u8_t*)p->payload + p->len <=\n                 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));\n    LWIP_ASSERT(\"PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT\",\n      (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );\n    /* set reference count (needed here in case we fail) */\n    p->ref = 1;\n\n    /* now allocate the tail of the pbuf chain */\n\n    /* remember first pbuf for linkage in next iteration */\n    r = p;\n    /* remaining length to be allocated */\n    rem_len = length - p->len;\n    /* any remaining pbufs to be allocated? */\n    while (rem_len > 0) {\n      q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL);\n      if (q == NULL) {\n        PBUF_POOL_IS_EMPTY();\n        /* free chain so far allocated */\n        pbuf_free(p);\n        /* bail out unsuccesfully */\n        return NULL;\n      }\n      q->type = type;\n      q->flags = 0;\n      q->next = NULL;\n      /* make previous pbuf point to this pbuf */\n      r->next = q;\n      /* set total length of this pbuf and next in chain */\n      LWIP_ASSERT(\"rem_len < max_u16_t\", rem_len < 0xffff);\n      q->tot_len = (u16_t)rem_len;\n      /* this pbuf length is pool size, unless smaller sized tail */\n      q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);\n      q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);\n      LWIP_ASSERT(\"pbuf_alloc: pbuf q->payload properly aligned\",\n              ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);\n      LWIP_ASSERT(\"check p->payload + p->len does not overflow pbuf\",\n                  ((u8_t*)p->payload + p->len <=\n                   (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));\n      q->ref = 1;\n      /* calculate remaining length to be allocated */\n      rem_len -= q->len;\n      /* remember this pbuf for linkage in next iteration */\n      r = q;\n    }\n    /* end of chain */\n    /*r->next = NULL;*/\n\n    break;\n  case PBUF_RAM:\n    /* If pbuf is to be allocated in RAM, allocate memory for it. */\n    p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));\n    if (p == NULL) {\n      return NULL;\n    }\n    /* Set up internal structure of the pbuf. */\n    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));\n    p->len = p->tot_len = length;\n    p->next = NULL;\n    p->type = type;\n    p->eb = NULL;\n\n    LWIP_ASSERT(\"pbuf_alloc: pbuf->payload properly aligned\",\n           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);\n    break;\n#ifdef EBUF_LWIP\n  case PBUF_ESF_RX:\n#endif /* ESF_LWIP */\n  /* pbuf references existing (non-volatile static constant) ROM payload? */\n  case PBUF_ROM:\n  /* pbuf references existing (externally allocated) RAM payload? */\n  case PBUF_REF:\n    /* only allocate memory for the pbuf structure */\n    p = (struct pbuf *)memp_malloc(MEMP_PBUF);\n    if (p == NULL) {\n      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n                  (\"pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\\n\",\n                  (type == PBUF_ROM) ? \"ROM\" : \"REF\"));\n      return NULL;\n    }\n    /* caller must set this field properly, afterwards */\n    p->payload = NULL;\n    p->len = p->tot_len = length;\n    p->next = NULL;\n    p->type = type;\n    break;\n  default:\n    LWIP_ASSERT(\"pbuf_alloc: erroneous type\", 0);\n    return NULL;\n  }\n  /* set reference count */\n  p->ref = 1;\n  /* set flags */\n  p->flags = 0;\n  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_alloc(length=%\"U16_F\") == %p\\n\", length, (void *)p));\n\n  return p;\n}\n\n#if LWIP_SUPPORT_CUSTOM_PBUF\n/** Initialize a custom pbuf (already allocated).\n *\n * @param layer flag to define header size\n * @param length size of the pbuf's payload\n * @param type type of the pbuf (only used to treat the pbuf accordingly, as\n *        this function allocates no memory)\n * @param p pointer to the custom pbuf to initialize (already allocated)\n * @param payload_mem pointer to the buffer that is used for payload and headers,\n *        must be at least big enough to hold 'length' plus the header size,\n *        may be NULL if set later\n * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least\n *        big enough to hold 'length' plus the header size\n */\nstruct pbuf*\npbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p,\n                    void *payload_mem, u16_t payload_mem_len)\n{\n  u16_t offset;\n  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_alloced_custom(length=%\"U16_F\")\\n\", length));\n\n  /* determine header offset */\n  offset = 0;\n  switch (l) {\n  case PBUF_TRANSPORT:\n    /* add room for transport (often TCP) layer header */\n    offset += PBUF_TRANSPORT_HLEN;\n    /* FALLTHROUGH */\n  case PBUF_IP:\n    /* add room for IP layer header */\n    offset += PBUF_IP_HLEN;\n    /* FALLTHROUGH */\n  case PBUF_LINK:\n    /* add room for link layer header */\n    offset += PBUF_LINK_HLEN;\n    break;\n  case PBUF_RAW:\n    break;\n  default:\n    LWIP_ASSERT(\"pbuf_alloced_custom: bad pbuf layer\", 0);\n    return NULL;\n  }\n\n  if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {\n    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, (\"pbuf_alloced_custom(length=%\"U16_F\") buffer too short\\n\", length));\n    return NULL;\n  }\n\n  p->pbuf.next = NULL;\n  if (payload_mem != NULL) {\n    p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset));\n  } else {\n    p->pbuf.payload = NULL;\n  }\n  p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;\n  p->pbuf.len = p->pbuf.tot_len = length;\n  p->pbuf.type = type;\n  p->pbuf.ref = 1;\n  return &p->pbuf;\n}\n#endif /* LWIP_SUPPORT_CUSTOM_PBUF */\n\n/**\n * Shrink a pbuf chain to a desired length.\n *\n * @param p pbuf to shrink.\n * @param new_len desired new length of pbuf chain\n *\n * Depending on the desired length, the first few pbufs in a chain might\n * be skipped and left unchanged. The new last pbuf in the chain will be\n * resized, and any remaining pbufs will be freed.\n *\n * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.\n * @note May not be called on a packet queue.\n *\n * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).\n */\nvoid\npbuf_realloc(struct pbuf *p, u16_t new_len)\n{\n  struct pbuf *q;\n  u16_t rem_len; /* remaining length */\n  s32_t grow;\n\n  LWIP_ASSERT(\"pbuf_realloc: p != NULL\", p != NULL);\n  LWIP_ASSERT(\"pbuf_realloc: sane p->type\", p->type == PBUF_POOL ||\n              p->type == PBUF_ROM ||\n              p->type == PBUF_RAM ||\n              p->type == PBUF_REF);\n\n  /* desired length larger than current length? */\n  if (new_len >= p->tot_len) {\n    /* enlarging not yet supported */\n    return;\n  }\n\n  /* the pbuf chain grows by (new_len - p->tot_len) bytes\n   * (which may be negative in case of shrinking) */\n  grow = new_len - p->tot_len;\n\n  /* first, step over any pbufs that should remain in the chain */\n  rem_len = new_len;\n  q = p;\n  /* should this pbuf be kept? */\n  while (rem_len > q->len) {\n    /* decrease remaining length by pbuf length */\n    rem_len -= q->len;\n    /* decrease total length indicator */\n    LWIP_ASSERT(\"grow < max_u16_t\", grow < 0xffff);\n    q->tot_len += (u16_t)grow;\n    /* proceed to next pbuf in chain */\n    q = q->next;\n    LWIP_ASSERT(\"pbuf_realloc: q != NULL\", q != NULL);\n  }\n  /* we have now reached the new last pbuf (in q) */\n  /* rem_len == desired length for pbuf q */\n\n  /* shrink allocated memory for PBUF_RAM */\n  /* (other types merely adjust their length fields */\n  if ((q->type == PBUF_RAM) && (rem_len != q->len)) {\n    /* reallocate and adjust the length of the pbuf that will be split */\n    q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len);\n    LWIP_ASSERT(\"mem_trim returned q == NULL\", q != NULL);\n  }\n  /* adjust length fields for new last pbuf */\n  q->len = rem_len;\n  q->tot_len = q->len;\n\n  /* any remaining pbufs in chain? */\n  if (q->next != NULL) {\n    /* free remaining pbufs in chain */\n    pbuf_free(q->next);\n  }\n  /* q is last packet in chain */\n  q->next = NULL;\n\n}\n\n/**\n * Adjusts the payload pointer to hide or reveal headers in the payload.\n *\n * Adjusts the ->payload pointer so that space for a header\n * (dis)appears in the pbuf payload.\n *\n * The ->payload, ->tot_len and ->len fields are adjusted.\n *\n * @param p pbuf to change the header size.\n * @param header_size_increment Number of bytes to increment header size which\n * increases the size of the pbuf. New space is on the front.\n * (Using a negative value decreases the header size.)\n * If hdr_size_inc is 0, this function does nothing and returns succesful.\n *\n * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so\n * the call will fail. A check is made that the increase in header size does\n * not move the payload pointer in front of the start of the buffer.\n * @return non-zero on failure, zero on success.\n *\n */\nu8_t\npbuf_header(struct pbuf *p, s16_t header_size_increment)\n{\n  u16_t type;\n  void *payload;\n  u16_t increment_magnitude;\n\n  LWIP_ASSERT(\"p != NULL\", p != NULL);\n  if ((header_size_increment == 0) || (p == NULL)) {\n    return 0;\n  }\n \n  if (header_size_increment < 0){\n    increment_magnitude = -header_size_increment;\n    /* Check that we aren't going to move off the end of the pbuf */\n    LWIP_ERROR(\"increment_magnitude <= p->len\", (increment_magnitude <= p->len), return 1;);\n  } else {\n    increment_magnitude = header_size_increment;\n#if 0\n    /* Can't assert these as some callers speculatively call\n         pbuf_header() to see if it's OK.  Will return 1 below instead. */\n    /* Check that we've got the correct type of pbuf to work with */\n    LWIP_ASSERT(\"p->type == PBUF_RAM || p->type == PBUF_POOL\", \n                p->type == PBUF_RAM || p->type == PBUF_POOL);\n    /* Check that we aren't going to move off the beginning of the pbuf */\n    LWIP_ASSERT(\"p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF\",\n                (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);\n#endif\n  }\n\n  type = p->type;\n  /* remember current payload pointer */\n  payload = p->payload;\n\n  /* pbuf types containing payloads? */\n  if (type == PBUF_RAM || type == PBUF_POOL) {\n    /* set new payload pointer */\n    p->payload = (u8_t *)p->payload - header_size_increment;\n    /* boundary check fails? */\n    if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF + EP_OFFSET) {\n      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n        (\"pbuf_header: failed as %p < %p (not enough space for new header size)\\n\",\n        (void *)p->payload, (void *)(p + 1)));\n      /* restore old payload pointer */\n      p->payload = payload;\n      /* bail out unsuccesfully */\n      return 1;\n    }\n  /* pbuf types refering to external payloads? */\n  } else if (type == PBUF_REF || type == PBUF_ROM) {\n    /* hide a header in the payload? */\n    if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {\n      /* increase payload pointer */\n      p->payload = (u8_t *)p->payload - header_size_increment;\n    } else {\n      /* cannot expand payload to front (yet!)\n       * bail out unsuccesfully */\n      if (type == PBUF_REF) {\n    \t  /* increase payload pointer */\n        p->payload = (u8_t *)p->payload - header_size_increment;\n      } else {\n        return 1;\n      }\n    }\n  } else {\n    /* Unknown type */\n    LWIP_ASSERT(\"bad pbuf type\", 0);\n    return 1;\n  }\n  /* modify pbuf length fields */\n  p->len += header_size_increment;\n  p->tot_len += header_size_increment;\n\n  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_header: old %p new %p (%\"S16_F\")\\n\",\n    (void *)payload, (void *)p->payload, header_size_increment));\n\n  return 0;\n}\n\n/**\n * Dereference a pbuf chain or queue and deallocate any no-longer-used\n * pbufs at the head of this chain or queue.\n *\n * Decrements the pbuf reference count. If it reaches zero, the pbuf is\n * deallocated.\n *\n * For a pbuf chain, this is repeated for each pbuf in the chain,\n * up to the first pbuf which has a non-zero reference count after\n * decrementing. So, when all reference counts are one, the whole\n * chain is free'd.\n *\n * @param p The pbuf (chain) to be dereferenced.\n *\n * @return the number of pbufs that were de-allocated\n * from the head of the chain.\n *\n * @note MUST NOT be called on a packet queue (Not verified to work yet).\n * @note the reference counter of a pbuf equals the number of pointers\n * that refer to the pbuf (or into the pbuf).\n *\n * @internal examples:\n *\n * Assuming existing chains a->b->c with the following reference\n * counts, calling pbuf_free(a) results in:\n * \n * 1->2->3 becomes ...1->3\n * 3->3->3 becomes 2->3->3\n * 1->1->2 becomes ......1\n * 2->1->1 becomes 1->1->1\n * 1->1->1 becomes .......\n *\n */\nu8_t\npbuf_free(struct pbuf *p)\n{\n  u16_t type;\n  struct pbuf *q;\n  u8_t count;\n\n  if (p == NULL) {\n    LWIP_ASSERT(\"p != NULL\", p != NULL);\n    /* if assertions are disabled, proceed with debug output */\n    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n      (\"pbuf_free(p == NULL) was called.\\n\"));\n    return 0;\n  }\n  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_free(%p)\\n\", (void *)p));\n\n  PERF_START;\n\n  LWIP_ASSERT(\"pbuf_free: sane type\",\n    p->type == PBUF_RAM || p->type == PBUF_ROM ||\n    p->type == PBUF_REF || p->type == PBUF_POOL \n#ifdef EBUF_LWIP\n    || p->type == PBUF_ESF_RX\n#endif  //EBUF_LWIP\n  );\n\n  count = 0;\n  /* de-allocate all consecutive pbufs from the head of the chain that\n   * obtain a zero reference count after decrementing*/\n  while (p != NULL) {\n    u16_t ref;\n    SYS_ARCH_DECL_PROTECT(old_level);\n    /* Since decrementing ref cannot be guaranteed to be a single machine operation\n     * we must protect it. We put the new ref into a local variable to prevent\n     * further protection. */\n    SYS_ARCH_PROTECT(old_level);\n    /* all pbufs in a chain are referenced at least once */\n    LWIP_ASSERT(\"pbuf_free: p->ref > 0\", p->ref > 0);\n    /* decrease reference count (number of pointers to pbuf) */\n    ref = --(p->ref);\n    SYS_ARCH_UNPROTECT(old_level);\n    /* this pbuf is no longer referenced to? */\n    if (ref == 0) {\n      /* remember next pbuf in chain for next iteration */\n      q = p->next;\n      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_free: deallocating %p\\n\", (void *)p));\n      type = p->type;\n#if LWIP_SUPPORT_CUSTOM_PBUF\n      /* is this a custom pbuf? */\n      if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {\n        struct pbuf_custom *pc = (struct pbuf_custom*)p;\n        LWIP_ASSERT(\"pc->custom_free_function != NULL\", pc->custom_free_function != NULL);\n        pc->custom_free_function(p);\n      } else\n#endif /* LWIP_SUPPORT_CUSTOM_PBUF */\n      {\n      /* is this a pbuf from the pool? */\n      if (type == PBUF_POOL) {\n        memp_free(MEMP_PBUF_POOL, p);\n      /* is this a ROM or RAM referencing pbuf? */\n      } else if (type == PBUF_ROM || type == PBUF_REF\n#ifdef EBUF_LWIP\n              || type == PBUF_ESF_RX\n#endif //EBUF_LWIP\n      ) {\n#ifdef EBUF_LWIP\n        system_pp_recycle_rx_pkt(p->eb);\n#endif //EBUF_LWIP\n        memp_free(MEMP_PBUF, p);\n      /* type == PBUF_RAM */\n      } else {\n        mem_free(p);\n      }\n      }\n      count++;\n      /* proceed to next pbuf */\n      p = q;\n    /* p->ref > 0, this pbuf is still referenced to */\n    /* (and so the remaining pbufs in chain as well) */\n    } else {\n      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_free: %p has ref %\"U16_F\", ending here.\\n\", (void *)p, ref));\n      /* stop walking through the chain */\n      p = NULL;\n    }\n  }\n  PERF_STOP(\"pbuf_free\");\n  /* return number of de-allocated pbufs */\n  return count;\n}\n\n/**\n * Count number of pbufs in a chain\n *\n * @param p first pbuf of chain\n * @return the number of pbufs in a chain\n */\n\nu8_t\npbuf_clen(struct pbuf *p)\n{\n  u8_t len;\n\n  len = 0;\n  while (p != NULL) {\n    ++len;\n    p = p->next;\n  }\n  return len;\n}\n\n/**\n * Increment the reference count of the pbuf.\n *\n * @param p pbuf to increase reference counter of\n *\n */\nvoid\npbuf_ref(struct pbuf *p)\n{\n  SYS_ARCH_DECL_PROTECT(old_level);\n  /* pbuf given? */\n  if (p != NULL) {\n    SYS_ARCH_PROTECT(old_level);\n    ++(p->ref);\n    SYS_ARCH_UNPROTECT(old_level);\n  }\n}\n\n/**\n * Concatenate two pbufs (each may be a pbuf chain) and take over\n * the caller's reference of the tail pbuf.\n * \n * @note The caller MAY NOT reference the tail pbuf afterwards.\n * Use pbuf_chain() for that purpose.\n * \n * @see pbuf_chain()\n */\n\nvoid\npbuf_cat(struct pbuf *h, struct pbuf *t)\n{\n  struct pbuf *p;\n\n  LWIP_ERROR(\"(h != NULL) && (t != NULL) (programmer violates API)\",\n             ((h != NULL) && (t != NULL)), return;);\n\n  /* proceed to last pbuf of chain */\n  for (p = h; p->next != NULL; p = p->next) {\n    /* add total length of second chain to all totals of first chain */\n    p->tot_len += t->tot_len;\n  }\n  /* { p is last pbuf of first h chain, p->next == NULL } */\n  LWIP_ASSERT(\"p->tot_len == p->len (of last pbuf in chain)\", p->tot_len == p->len);\n  LWIP_ASSERT(\"p->next == NULL\", p->next == NULL);\n  /* add total length of second chain to last pbuf total of first chain */\n  p->tot_len += t->tot_len;\n  /* chain last pbuf of head (p) with first of tail (t) */\n  p->next = t;\n  /* p->next now references t, but the caller will drop its reference to t,\n   * so netto there is no change to the reference count of t.\n   */\n}\n\n/**\n * Chain two pbufs (or pbuf chains) together.\n * \n * The caller MUST call pbuf_free(t) once it has stopped\n * using it. Use pbuf_cat() instead if you no longer use t.\n * \n * @param h head pbuf (chain)\n * @param t tail pbuf (chain)\n * @note The pbufs MUST belong to the same packet.\n * @note MAY NOT be called on a packet queue.\n *\n * The ->tot_len fields of all pbufs of the head chain are adjusted.\n * The ->next field of the last pbuf of the head chain is adjusted.\n * The ->ref field of the first pbuf of the tail chain is adjusted.\n *\n */\nvoid\npbuf_chain(struct pbuf *h, struct pbuf *t)\n{\n  pbuf_cat(h, t);\n  /* t is now referenced by h */\n  pbuf_ref(t);\n  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_chain: %p references %p\\n\", (void *)h, (void *)t));\n}\n\n/**\n * Dechains the first pbuf from its succeeding pbufs in the chain.\n *\n * Makes p->tot_len field equal to p->len.\n * @param p pbuf to dechain\n * @return remainder of the pbuf chain, or NULL if it was de-allocated.\n * @note May not be called on a packet queue.\n */\nstruct pbuf *\npbuf_dechain(struct pbuf *p)\n{\n  struct pbuf *q;\n  u8_t tail_gone = 1;\n  /* tail */\n  q = p->next;\n  /* pbuf has successor in chain? */\n  if (q != NULL) {\n    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\n    LWIP_ASSERT(\"p->tot_len == p->len + q->tot_len\", q->tot_len == p->tot_len - p->len);\n    /* enforce invariant if assertion is disabled */\n    q->tot_len = p->tot_len - p->len;\n    /* decouple pbuf from remainder */\n    p->next = NULL;\n    /* total length of pbuf p is its own length only */\n    p->tot_len = p->len;\n    /* q is no longer referenced by p, free it */\n    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_dechain: unreferencing %p\\n\", (void *)q));\n    tail_gone = pbuf_free(q);\n    if (tail_gone > 0) {\n      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,\n                  (\"pbuf_dechain: deallocated %p (as it is no longer referenced)\\n\", (void *)q));\n    }\n    /* return remaining tail or NULL if deallocated */\n  }\n  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\n  LWIP_ASSERT(\"p->tot_len == p->len\", p->tot_len == p->len);\n  return ((tail_gone > 0) ? NULL : q);\n}\n\n/**\n *\n * Create PBUF_RAM copies of pbufs.\n *\n * Used to queue packets on behalf of the lwIP stack, such as\n * ARP based queueing.\n *\n * @note You MUST explicitly use p = pbuf_take(p);\n *\n * @note Only one packet is copied, no packet queue!\n *\n * @param p_to pbuf destination of the copy\n * @param p_from pbuf source of the copy\n *\n * @return ERR_OK if pbuf was copied\n *         ERR_ARG if one of the pbufs is NULL or p_to is not big\n *                 enough to hold p_from\n */\nerr_t\npbuf_copy(struct pbuf *p_to, struct pbuf *p_from)\n{\n  u16_t offset_to=0, offset_from=0, len;\n\n  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_copy(%p, %p)\\n\",\n    (void*)p_to, (void*)p_from));\n\n  /* is the target big enough to hold the source? */\n  LWIP_ERROR(\"pbuf_copy: target not big enough to hold source\", ((p_to != NULL) &&\n             (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);\n\n  /* iterate through pbuf chain */\n  do\n  {\n    LWIP_ASSERT(\"p_to != NULL\", p_to != NULL);\n    /* copy one part of the original chain */\n    if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {\n      /* complete current p_from fits into current p_to */\n      len = p_from->len - offset_from;\n    } else {\n      /* current p_from does not fit into current p_to */\n      len = p_to->len - offset_to;\n    }\n    MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);\n    offset_to += len;\n    offset_from += len;\n    LWIP_ASSERT(\"offset_to <= p_to->len\", offset_to <= p_to->len);\n    if (offset_to == p_to->len) {\n      /* on to next p_to (if any) */\n      offset_to = 0;\n      p_to = p_to->next;\n    }\n    LWIP_ASSERT(\"offset_from <= p_from->len\", offset_from <= p_from->len);\n    if (offset_from >= p_from->len) {\n      /* on to next p_from (if any) */\n      offset_from = 0;\n      p_from = p_from->next;\n    }\n\n    if((p_from != NULL) && (p_from->len == p_from->tot_len)) {\n      /* don't copy more than one packet! */\n      LWIP_ERROR(\"pbuf_copy() does not allow packet queues!\\n\",\n                 (p_from->next == NULL), return ERR_VAL;);\n    }\n    if((p_to != NULL) && (p_to->len == p_to->tot_len)) {\n      /* don't copy more than one packet! */\n      LWIP_ERROR(\"pbuf_copy() does not allow packet queues!\\n\",\n                  (p_to->next == NULL), return ERR_VAL;);\n    }\n  } while (p_from);\n  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, (\"pbuf_copy: end of chain reached.\\n\"));\n  return ERR_OK;\n}\n\n/**\n * Copy (part of) the contents of a packet buffer\n * to an application supplied buffer.\n *\n * @param buf the pbuf from which to copy data\n * @param dataptr the application supplied buffer\n * @param len length of data to copy (dataptr must be big enough). No more \n * than buf->tot_len will be copied, irrespective of len\n * @param offset offset into the packet buffer from where to begin copying len bytes\n * @return the number of bytes copied, or 0 on failure\n */\nu16_t\npbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)\n{\n  struct pbuf *p;\n  u16_t left;\n  u16_t buf_copy_len;\n  u16_t copied_total = 0;\n\n  LWIP_ERROR(\"pbuf_copy_partial: invalid buf\", (buf != NULL), return 0;);\n  LWIP_ERROR(\"pbuf_copy_partial: invalid dataptr\", (dataptr != NULL), return 0;);\n\n  left = 0;\n\n  if((buf == NULL) || (dataptr == NULL)) {\n    return 0;\n  }\n\n  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */\n  for(p = buf; len != 0 && p != NULL; p = p->next) {\n    if ((offset != 0) && (offset >= p->len)) {\n      /* don't copy from this buffer -> on to the next */\n      offset -= p->len;\n    } else {\n      /* copy from this buffer. maybe only partially. */\n      buf_copy_len = p->len - offset;\n      if (buf_copy_len > len)\n          buf_copy_len = len;\n      /* copy the necessary parts of the buffer */\n      MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);\n      copied_total += buf_copy_len;\n      left += buf_copy_len;\n      len -= buf_copy_len;\n      offset = 0;\n    }\n  }\n  return copied_total;\n}\n\n/**\n * Copy application supplied data into a pbuf.\n * This function can only be used to copy the equivalent of buf->tot_len data.\n *\n * @param buf pbuf to fill with data\n * @param dataptr application supplied data buffer\n * @param len length of the application supplied data buffer\n *\n * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough\n */\nerr_t\npbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)\n{\n  struct pbuf *p;\n  u16_t buf_copy_len;\n  u16_t total_copy_len = len;\n  u16_t copied_total = 0;\n\n  LWIP_ERROR(\"pbuf_take: invalid buf\", (buf != NULL), return 0;);\n  LWIP_ERROR(\"pbuf_take: invalid dataptr\", (dataptr != NULL), return 0;);\n\n  if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {\n    return ERR_ARG;\n  }\n\n  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */\n  for(p = buf; total_copy_len != 0; p = p->next) {\n    LWIP_ASSERT(\"pbuf_take: invalid pbuf\", p != NULL);\n    buf_copy_len = total_copy_len;\n    if (buf_copy_len > p->len) {\n      /* this pbuf cannot hold all remaining data */\n      buf_copy_len = p->len;\n    }\n    /* copy the necessary parts of the buffer */\n    MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);\n    total_copy_len -= buf_copy_len;\n    copied_total += buf_copy_len;\n  }\n  LWIP_ASSERT(\"did not copy all data\", total_copy_len == 0 && copied_total == len);\n  return ERR_OK;\n}\n\n/**\n * Creates a single pbuf out of a queue of pbufs.\n *\n * @remark: Either the source pbuf 'p' is freed by this function or the original\n *          pbuf 'p' is returned, therefore the caller has to check the result!\n *\n * @param p the source pbuf\n * @param layer pbuf_layer of the new pbuf\n *\n * @return a new, single pbuf (p->next is NULL)\n *         or the old pbuf if allocation fails\n */\nstruct pbuf*\npbuf_coalesce(struct pbuf *p, pbuf_layer layer)\n{\n  struct pbuf *q;\n  err_t err;\n  if (p->next == NULL) {\n    return p;\n  }\n  q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);\n  if (q == NULL) {\n    /* @todo: what do we do now? */\n    return p;\n  }\n  err = pbuf_copy(q, p);\n  LWIP_ASSERT(\"pbuf_copy failed\", err == ERR_OK);\n  pbuf_free(p);\n  return q;\n}\n\n#if LWIP_CHECKSUM_ON_COPY\n/**\n * Copies data into a single pbuf (*not* into a pbuf queue!) and updates\n * the checksum while copying\n *\n * @param p the pbuf to copy data into\n * @param start_offset offset of p->payload where to copy the data to\n * @param dataptr data to copy into the pbuf\n * @param len length of data to copy into the pbuf\n * @param chksum pointer to the checksum which is updated\n * @return ERR_OK if successful, another error if the data does not fit\n *         within the (first) pbuf (no pbuf queues!)\n */\nerr_t\npbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,\n                 u16_t len, u16_t *chksum)\n{\n  u32_t acc;\n  u16_t copy_chksum;\n  char *dst_ptr;\n  LWIP_ASSERT(\"p != NULL\", p != NULL);\n  LWIP_ASSERT(\"dataptr != NULL\", dataptr != NULL);\n  LWIP_ASSERT(\"chksum != NULL\", chksum != NULL);\n  LWIP_ASSERT(\"len != 0\", len != 0);\n\n  if ((start_offset >= p->len) || (start_offset + len > p->len)) {\n    return ERR_ARG;\n  }\n\n  dst_ptr = ((char*)p->payload) + start_offset;\n  copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);\n  if ((start_offset & 1) != 0) {\n    copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);\n  }\n  acc = *chksum;\n  acc += copy_chksum;\n  *chksum = FOLD_U32T(acc);\n  return ERR_OK;\n}\n#endif /* LWIP_CHECKSUM_ON_COPY */\n\n /** Get one byte from the specified position in a pbuf\n * WARNING: returns zero for offset >= p->tot_len\n *\n * @param p pbuf to parse\n * @param offset offset into p of the byte to return\n * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len\n */\nu8_t\npbuf_get_at(struct pbuf* p, u16_t offset)\n{\n  u16_t copy_from = offset;\n  struct pbuf* q = p;\n\n  /* get the correct pbuf */\n  while ((q != NULL) && (q->len <= copy_from)) {\n    copy_from -= q->len;\n    q = q->next;\n  }\n  /* return requested data if pbuf is OK */\n  if ((q != NULL) && (q->len > copy_from)) {\n    return ((u8_t*)q->payload)[copy_from];\n  }\n  return 0;\n}\n\n/** Compare pbuf contents at specified offset with memory s2, both of length n\n *\n * @param p pbuf to compare\n * @param offset offset into p at wich to start comparing\n * @param s2 buffer to compare\n * @param n length of buffer to compare\n * @return zero if equal, nonzero otherwise\n *         (0xffff if p is too short, diffoffset+1 otherwise)\n */\nu16_t\npbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n)\n{\n  u16_t start = offset;\n  struct pbuf* q = p;\n\n  /* get the correct pbuf */\n  while ((q != NULL) && (q->len <= start)) {\n    start -= q->len;\n    q = q->next;\n  }\n  /* return requested data if pbuf is OK */\n  if ((q != NULL) && (q->len > start)) {\n    u16_t i;\n    for(i = 0; i < n; i++) {\n      u8_t a = pbuf_get_at(q, start + i);\n      u8_t b = ((u8_t*)s2)[i];\n      if (a != b) {\n        return i+1;\n      }\n    }\n    return 0;\n  }\n  return 0xffff;\n}\n\n/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset\n * start_offset.\n *\n * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as\n *        return value 'not found'\n * @param mem search for the contents of this buffer\n * @param mem_len length of 'mem'\n * @param start_offset offset into p at which to start searching\n * @return 0xFFFF if substr was not found in p or the index where it was found\n */\nu16_t\npbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset)\n{\n  u16_t i;\n  u16_t max = p->tot_len - mem_len;\n  if (p->tot_len >= mem_len + start_offset) {\n    for(i = start_offset; i <= max; ) {\n      u16_t plus = pbuf_memcmp(p, i, mem, mem_len);\n      if (plus == 0) {\n        return i;\n      } else {\n        i += plus;\n      }\n    }\n  }\n  return 0xFFFF;\n}\n\n/** Find occurrence of substr with length substr_len in pbuf p, start at offset\n * start_offset\n * WARNING: in contrast to strstr(), this one does not stop at the first \\0 in\n * the pbuf/source string!\n *\n * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as\n *        return value 'not found'\n * @param substr string to search for in p, maximum length is 0xFFFE\n * @return 0xFFFF if substr was not found in p or the index where it was found\n */\nu16_t\npbuf_strstr(struct pbuf* p, const char* substr)\n{\n  size_t substr_len;\n  if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {\n    return 0xFFFF;\n  }\n  substr_len = os_strlen(substr);\n  if (substr_len >= 0xFFFF) {\n    return 0xFFFF;\n  }\n  return pbuf_memfind(p, substr, (u16_t)substr_len, 0);\n}\n"
  },
  {
    "path": "app/lwip/core/raw.c",
    "content": "/**\n * @file\n * Implementation of raw protocol PCBs for low-level handling of\n * different types of protocols besides (or overriding) those\n * already available in lwIP.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/def.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/raw.h\"\n#include \"lwip/stats.h\"\n#include \"arch/perf.h\"\n\n#include <string.h>\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/** The list of RAW PCBs */\nstatic struct raw_pcb *raw_pcbs;\n\n/**\n * Determine if in incoming IP packet is covered by a RAW PCB\n * and if so, pass it to a user-provided receive callback function.\n *\n * Given an incoming IP datagram (as a chain of pbufs) this function\n * finds a corresponding RAW PCB and calls the corresponding receive\n * callback function.\n *\n * @param p pbuf to be demultiplexed to a RAW PCB.\n * @param inp network interface on which the datagram was received.\n * @return - 1 if the packet has been eaten by a RAW PCB receive\n *           callback function. The caller MAY NOT not reference the\n *           packet any longer, and MAY NOT call pbuf_free().\n * @return - 0 if packet is not eaten (pbuf is still referenced by the\n *           caller).\n *\n */\nu8_t ICACHE_FLASH_ATTR\nraw_input(struct pbuf *p, struct netif *inp)\n{\n  struct raw_pcb *pcb, *prev;\n  struct ip_hdr *iphdr;\n  s16_t proto;\n  u8_t eaten = 0;\n\n  LWIP_UNUSED_ARG(inp);\n\n  iphdr = (struct ip_hdr *)p->payload;\n  proto = IPH_PROTO(iphdr);\n\n  prev = NULL;\n  pcb = raw_pcbs;\n  /* loop through all raw pcbs until the packet is eaten by one */\n  /* this allows multiple pcbs to match against the packet by design */\n  while ((eaten == 0) && (pcb != NULL)) {\n    if ((pcb->protocol == proto) &&\n        (ip_addr_isany(&pcb->local_ip) ||\n         ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest))) {\n#if IP_SOF_BROADCAST_RECV\n      /* broadcast filter? */\n      if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&current_iphdr_dest, inp))\n#endif /* IP_SOF_BROADCAST_RECV */\n      {\n        /* receive callback function available? */\n        if (pcb->recv != NULL) {\n          /* the receive callback function did not eat the packet? */\n          if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {\n            /* receive function ate the packet */\n            p = NULL;\n            eaten = 1;\n            if (prev != NULL) {\n            /* move the pcb to the front of raw_pcbs so that is\n               found faster next time */\n              prev->next = pcb->next;\n              pcb->next = raw_pcbs;\n              raw_pcbs = pcb;\n            }\n          }\n        }\n        /* no receive callback function was set for this raw PCB */\n      }\n      /* drop the packet */\n    }\n    prev = pcb;\n    pcb = pcb->next;\n  }\n  return eaten;\n}\n\n/**\n * Bind a RAW PCB.\n *\n * @param pcb RAW PCB to be bound with a local address ipaddr.\n * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to\n * bind to all local interfaces.\n *\n * @return lwIP error code.\n * - ERR_OK. Successful. No error occured.\n * - ERR_USE. The specified IP address is already bound to by\n * another RAW PCB.\n *\n * @see raw_disconnect()\n */\nerr_t ICACHE_FLASH_ATTR\nraw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)\n{\n  ip_addr_set(&pcb->local_ip, ipaddr);\n  return ERR_OK;\n}\n\n/**\n * Connect an RAW PCB. This function is required by upper layers\n * of lwip. Using the raw api you could use raw_sendto() instead\n *\n * This will associate the RAW PCB with the remote address.\n *\n * @param pcb RAW PCB to be connected with remote address ipaddr and port.\n * @param ipaddr remote IP address to connect with.\n *\n * @return lwIP error code\n *\n * @see raw_disconnect() and raw_sendto()\n */\nerr_t ICACHE_FLASH_ATTR\nraw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)\n{\n  ip_addr_set(&pcb->remote_ip, ipaddr);\n  return ERR_OK;\n}\n\n\n/**\n * Set the callback function for received packets that match the\n * raw PCB's protocol and binding. \n * \n * The callback function MUST either\n * - eat the packet by calling pbuf_free() and returning non-zero. The\n *   packet will not be passed to other raw PCBs or other protocol layers.\n * - not free the packet, and return zero. The packet will be matched\n *   against further PCBs and/or forwarded to another protocol layers.\n * \n * @return non-zero if the packet was free()d, zero if the packet remains\n * available for others.\n */\nvoid ICACHE_FLASH_ATTR\nraw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)\n{\n  /* remember recv() callback and user data */\n  pcb->recv = recv;\n  pcb->recv_arg = recv_arg;\n}\n\n/**\n * Send the raw IP packet to the given address. Note that actually you cannot\n * modify the IP headers (this is inconsistent with the receive callback where\n * you actually get the IP headers), you can only specify the IP payload here.\n * It requires some more changes in lwIP. (there will be a raw_send() function\n * then.)\n *\n * @param pcb the raw pcb which to send\n * @param p the IP payload to send\n * @param ipaddr the destination address of the IP packet\n *\n */\nerr_t ICACHE_FLASH_ATTR\nraw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)\n{\n  err_t err;\n  struct netif *netif;\n  ip_addr_t *src_ip;\n  struct pbuf *q; /* q will be sent down the stack */\n  \n  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, (\"raw_sendto\\n\"));\n  \n  /* not enough space to add an IP header to first pbuf in given p chain? */\n  if (pbuf_header(p, IP_HLEN)) {\n    /* allocate header in new pbuf */\n    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);\n    /* new header pbuf could not be allocated? */\n    if (q == NULL) {\n      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"raw_sendto: could not allocate header\\n\"));\n      return ERR_MEM;\n    }\n    if (p->tot_len != 0) {\n      /* chain header q in front of given pbuf p */\n      pbuf_chain(q, p);\n    }\n    /* { first pbuf q points to header pbuf } */\n    LWIP_DEBUGF(RAW_DEBUG, (\"raw_sendto: added header pbuf %p before given pbuf %p\\n\", (void *)q, (void *)p));\n  }  else {\n    /* first pbuf q equals given pbuf */\n    q = p;\n    if(pbuf_header(q, -IP_HLEN)) {\n      LWIP_ASSERT(\"Can't restore header we just removed!\", 0);\n      return ERR_MEM;\n    }\n  }\n\n  if ((netif = ip_route(ipaddr)) == NULL) {\n    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, (\"raw_sendto: No route to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n      ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));\n    /* free any temporary header pbuf allocated by pbuf_header() */\n    if (q != p) {\n      pbuf_free(q);\n    }\n    return ERR_RTE;\n  }\n\n#if IP_SOF_BROADCAST\n  /* broadcast filter? */\n  if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {\n    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, (\"raw_sendto: SOF_BROADCAST not enabled on pcb %p\\n\", (void *)pcb));\n    /* free any temporary header pbuf allocated by pbuf_header() */\n    if (q != p) {\n      pbuf_free(q);\n    }\n    return ERR_VAL;\n  }\n#endif /* IP_SOF_BROADCAST */\n\n  if (ip_addr_isany(&pcb->local_ip)) {\n    /* use outgoing network interface IP address as source address */\n    src_ip = &(netif->ip_addr);\n  } else {\n    /* use RAW PCB local IP address as source address */\n    src_ip = &(pcb->local_ip);\n  }\n\n#if LWIP_NETIF_HWADDRHINT\n  netif->addr_hint = &(pcb->addr_hint);\n#endif /* LWIP_NETIF_HWADDRHINT*/\n  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);\n#if LWIP_NETIF_HWADDRHINT\n  netif->addr_hint = NULL;\n#endif /* LWIP_NETIF_HWADDRHINT*/\n\n  /* did we chain a header earlier? */\n  if (q != p) {\n    /* free the header */\n    pbuf_free(q);\n  }\n  return err;\n}\n\n/**\n * Send the raw IP packet to the address given by raw_connect()\n *\n * @param pcb the raw pcb which to send\n * @param p the IP payload to send\n *\n */\nerr_t ICACHE_FLASH_ATTR\nraw_send(struct raw_pcb *pcb, struct pbuf *p)\n{\n  return raw_sendto(pcb, p, &pcb->remote_ip);\n}\n\n/**\n * Remove an RAW PCB.\n *\n * @param pcb RAW PCB to be removed. The PCB is removed from the list of\n * RAW PCB's and the data structure is freed from memory.\n *\n * @see raw_new()\n */\nvoid ICACHE_FLASH_ATTR\nraw_remove(struct raw_pcb *pcb)\n{\n  struct raw_pcb *pcb2;\n  /* pcb to be removed is first in list? */\n  if (raw_pcbs == pcb) {\n    /* make list start at 2nd pcb */\n    raw_pcbs = raw_pcbs->next;\n    /* pcb not 1st in list */\n  } else {\n    for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {\n      /* find pcb in raw_pcbs list */\n      if (pcb2->next != NULL && pcb2->next == pcb) {\n        /* remove pcb from list */\n        pcb2->next = pcb->next;\n      }\n    }\n  }\n  memp_free(MEMP_RAW_PCB, pcb);\n}\n\n/**\n * Create a RAW PCB.\n *\n * @return The RAW PCB which was created. NULL if the PCB data structure\n * could not be allocated.\n *\n * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)\n *\n * @see raw_remove()\n */\nstruct raw_pcb * ICACHE_FLASH_ATTR\nraw_new(u8_t proto)\n{\n  struct raw_pcb *pcb;\n\n  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, (\"raw_new\\n\"));\n\n  pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);\n  /* could allocate RAW PCB? */\n  if (pcb != NULL) {\n    /* initialize PCB to all zeroes */\n    os_memset(pcb, 0, sizeof(struct raw_pcb));\n    pcb->protocol = proto;\n    pcb->ttl = RAW_TTL;\n    pcb->next = raw_pcbs;\n    raw_pcbs = pcb;\n  }\n  return pcb;\n}\n\n#endif /* LWIP_RAW */\n"
  },
  {
    "path": "app/lwip/core/sntp.c",
    "content": "/**\n * @file\n * SNTP client module\n *\n * This is simple \"SNTP\" client for the lwIP raw API.\n * It is a minimal implementation of SNTPv4 as specified in RFC 4330.\n * \n * For a list of some public NTP servers, see this link :\n * http://support.ntp.org/bin/view/Servers/NTPPoolServers\n *\n * @todo:\n * - set/change servers at runtime\n * - complete SNTP_CHECK_RESPONSE checks 3 and 4\n * - support broadcast/multicast mode?\n */\n\n/*\n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Simon Goldschmidt (lwIP raw API part)\n */\n\n#include \"lwip/sntp.h\"\n#include \"osapi.h\"\n#include \"os_type.h\"\n#include \"lwip/opt.h\"\n#include \"lwip/timers.h\"\n#include \"lwip/udp.h\"\n#include \"lwip/dns.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/pbuf.h\"\n\n//#include <string.h>\n#if LWIP_UDP\n\n/**\n * SNTP_DEBUG: Enable debugging for SNTP.\n */\n#ifndef SNTP_DEBUG\n#define SNTP_DEBUG                  LWIP_DBG_ON\n#endif\n\n/** SNTP server port */\n#ifndef SNTP_PORT\n#define SNTP_PORT                   123\n#endif\n\n/** Set this to 1 to allow config of SNTP server(s) by DNS name */\n#ifndef SNTP_SERVER_DNS\n#define SNTP_SERVER_DNS             0\n#endif\n\n/** Handle support for more than one server via NTP_MAX_SERVERS,\n * but catch legacy style of setting SNTP_SUPPORT_MULTIPLE_SERVERS, probably outside of this file\n */\n#ifndef SNTP_SUPPORT_MULTIPLE_SERVERS\n#if SNTP_MAX_SERVERS > 1\n#define SNTP_SUPPORT_MULTIPLE_SERVERS 1\n#else /* NTP_MAX_SERVERS > 1 */\n#define SNTP_SUPPORT_MULTIPLE_SERVERS 0\n#endif /* NTP_MAX_SERVERS > 1 */\n#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */\n/* The developer has defined SNTP_SUPPORT_MULTIPLE_SERVERS, probably from old code */\n#if SNTP_MAX_SERVERS <= 1\n#error \"SNTP_MAX_SERVERS needs to be defined to the max amount of servers if SNTP_SUPPORT_MULTIPLE_SERVERS is defined\"\n#endif /* SNTP_MAX_SERVERS <= 1 */\n#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */\n\n\n/** Sanity check:\n * Define this to\n * - 0 to turn off sanity checks (default; smaller code)\n * - >= 1 to check address and port of the response packet to ensure the\n *        response comes from the server we sent the request to.\n * - >= 2 to check returned Originate Timestamp against Transmit Timestamp\n *        sent to the server (to ensure response to older request).\n * - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp\n *        fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast).\n * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each\n *        greater than or equal to 0 and less than infinity, where infinity is\n *        currently a cozy number like one second. This check avoids using a\n *        server whose synchronization source has expired for a very long time.\n */\n#ifndef SNTP_CHECK_RESPONSE\n#define SNTP_CHECK_RESPONSE         0\n#endif\n\n/** According to the RFC, this shall be a random delay\n * between 1 and 5 minutes (in milliseconds) to prevent load peaks.\n * This can be defined to a random generation function,\n * which must return the delay in milliseconds as u32_t.\n * Turned off by default.\n */\n#ifndef SNTP_STARTUP_DELAY\n#define SNTP_STARTUP_DELAY          0\n#endif\n\n/** If you want the startup delay to be a function, define this\n * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1.\n */\n#ifndef SNTP_STARTUP_DELAY_FUNC\n#define SNTP_STARTUP_DELAY_FUNC     SNTP_STARTUP_DELAY\n#endif\n\n/** SNTP receive timeout - in milliseconds\n * Also used as retry timeout - this shouldn't be too low.\n * Default is 3 seconds.\n */\n#ifndef SNTP_RECV_TIMEOUT\n#define SNTP_RECV_TIMEOUT           3000\n#endif\n\n/** SNTP update delay - in milliseconds\n * Default is 1 hour.\n */\n#ifndef SNTP_UPDATE_DELAY\n#define SNTP_UPDATE_DELAY           3600000\n#endif\n#if (SNTP_UPDATE_DELAY < 15000) && !SNTP_SUPPRESS_DELAY_CHECK\n#error \"SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds!\"\n#endif\n\n/** SNTP macro to change system time and/or the update the RTC clock */\n#ifndef SNTP_SET_SYSTEM_TIME\n#define SNTP_SET_SYSTEM_TIME(sec) ((void)sec)\n#endif\n\n/** SNTP macro to change system time including microseconds */\n#ifdef SNTP_SET_SYSTEM_TIME_US\n#define SNTP_CALC_TIME_US           1\n#define SNTP_RECEIVE_TIME_SIZE      2\n#else\n#define SNTP_SET_SYSTEM_TIME_US(sec, us)\n#define SNTP_CALC_TIME_US           0\n#define SNTP_RECEIVE_TIME_SIZE      1\n#endif\n\n/** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2\n * to send in request and compare in response.\n */\n#ifndef SNTP_GET_SYSTEM_TIME\n#define SNTP_GET_SYSTEM_TIME(sec, us)     do { (sec) = 0; (us) = 0; } while(0)\n#endif\n\n/** Default retry timeout (in milliseconds) if the response\n * received is invalid.\n * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached.\n */\n#ifndef SNTP_RETRY_TIMEOUT\n#define SNTP_RETRY_TIMEOUT          SNTP_RECV_TIMEOUT\n#endif\n\n/** Maximum retry timeout (in milliseconds). */\n#ifndef SNTP_RETRY_TIMEOUT_MAX\n#define SNTP_RETRY_TIMEOUT_MAX      (SNTP_RETRY_TIMEOUT * 10)\n#endif\n\n/** Increase retry timeout with every retry sent\n * Default is on to conform to RFC.\n */\n#ifndef SNTP_RETRY_TIMEOUT_EXP\n#define SNTP_RETRY_TIMEOUT_EXP      1\n#endif\n\n/* the various debug levels for this file */\n#define SNTP_DEBUG_TRACE        (SNTP_DEBUG | LWIP_DBG_TRACE)\n#define SNTP_DEBUG_STATE        (SNTP_DEBUG | LWIP_DBG_STATE)\n#define SNTP_DEBUG_WARN         (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING)\n#define SNTP_DEBUG_WARN_STATE   (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE)\n#define SNTP_DEBUG_SERIOUS      (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS)\n\n#define SNTP_ERR_KOD                1\n\n/* SNTP protocol defines */\n#define SNTP_MSG_LEN                48\n\n#define SNTP_OFFSET_LI_VN_MODE      0\n#define SNTP_LI_MASK                0xC0\n#define SNTP_LI_NO_WARNING          0x00\n#define SNTP_LI_LAST_MINUTE_61_SEC  0x01\n#define SNTP_LI_LAST_MINUTE_59_SEC  0x02\n#define SNTP_LI_ALARM_CONDITION     0x03 /* (clock not synchronized) */\n\n#define SNTP_VERSION_MASK           0x38\n#define SNTP_VERSION                (4/* NTP Version 4*/<<3) \n\n#define SNTP_MODE_MASK              0x07\n#define SNTP_MODE_CLIENT            0x03\n#define SNTP_MODE_SERVER            0x04\n#define SNTP_MODE_BROADCAST         0x05\n\n#define SNTP_OFFSET_STRATUM         1\n#define SNTP_STRATUM_KOD            0x00\n\n#define SNTP_OFFSET_ORIGINATE_TIME  24\n#define SNTP_OFFSET_RECEIVE_TIME    32\n#define SNTP_OFFSET_TRANSMIT_TIME   40\n\n/* number of seconds between 1900 and 1970 */\n#define DIFF_SEC_1900_1970         (2208988800UL)\n\n/**\n * SNTP packet format (without optional fields)\n * Timestamps are coded as 64 bits:\n * - 32 bits seconds since Jan 01, 1970, 00:00\n * - 32 bits seconds fraction (0-padded)\n * For future use, if the MSB in the seconds part is set, seconds are based\n * on Feb 07, 2036, 06:28:16.\n */\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/bpstruct.h\"\n#endif\nPACK_STRUCT_BEGIN\n#define PACK_STRUCT_FLD_8 PACK_STRUCT_FIELD\nstruct sntp_msg {\n  PACK_STRUCT_FLD_8(u8_t           li_vn_mode);\n  PACK_STRUCT_FLD_8(u8_t           stratum);\n  PACK_STRUCT_FLD_8(u8_t           poll);\n  PACK_STRUCT_FLD_8(u8_t           precision);\n  PACK_STRUCT_FIELD(u32_t          root_delay);\n  PACK_STRUCT_FIELD(u32_t          root_dispersion);\n  PACK_STRUCT_FIELD(u32_t          reference_identifier);\n  PACK_STRUCT_FIELD(u32_t          reference_timestamp[2]);\n  PACK_STRUCT_FIELD(u32_t          originate_timestamp[2]);\n  PACK_STRUCT_FIELD(u32_t          receive_timestamp[2]);\n  PACK_STRUCT_FIELD(u32_t          transmit_timestamp[2]);\n} PACK_STRUCT_STRUCT;\nPACK_STRUCT_END\n#ifdef PACK_STRUCT_USE_INCLUDES\n#  include \"arch/epstruct.h\"\n#endif\n\n/* function prototypes */\nstatic void sntp_request(void *arg);\n\n/** The UDP pcb used by the SNTP client */\nstatic struct udp_pcb* sntp_pcb;\n\nsint8 time_zone = 8;\n/** Names/Addresses of servers */\nstruct sntp_server {\n#if SNTP_SERVER_DNS\n  char* name;\n#endif /* SNTP_SERVER_DNS */\n  ip_addr_t addr;\n};\nstatic struct sntp_server sntp_servers[SNTP_MAX_SERVERS];\n\nstatic u8_t sntp_set_servers_from_dhcp;\n#if SNTP_SUPPORT_MULTIPLE_SERVERS\n/** The currently used server (initialized to 0) */\nstatic u8_t sntp_current_server;\n#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */\n#define sntp_current_server 0\n#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */\n\n#if SNTP_RETRY_TIMEOUT_EXP\n#define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT\n/** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */\nstatic u32_t sntp_retry_timeout;\n#else /* SNTP_RETRY_TIMEOUT_EXP */\n#define SNTP_RESET_RETRY_TIMEOUT()\n#define sntp_retry_timeout SNTP_RETRY_TIMEOUT\n#endif /* SNTP_RETRY_TIMEOUT_EXP */\n\n#if SNTP_CHECK_RESPONSE >= 1\n/** Saves the last server address to compare with response */\nstatic ip_addr_t sntp_last_server_address;\n#endif /* SNTP_CHECK_RESPONSE >= 1 */\n\n#if SNTP_CHECK_RESPONSE >= 2\n/** Saves the last timestamp sent (which is sent back by the server)\n * to compare against in response */\nstatic u32_t sntp_last_timestamp_sent[2];\n#endif /* SNTP_CHECK_RESPONSE >= 2 */\ntypedef long     time_t;\n//uint32 current_stamp_1 = 0;\n//uint32 current_stamp_2 = 0;\nuint32 realtime_stamp = 0;\nLOCAL os_timer_t sntp_timer;\n/*****************************************/\n#define SECSPERMIN\t60L\n#define MINSPERHOUR\t60L\n#define HOURSPERDAY\t24L\n#define SECSPERHOUR\t(SECSPERMIN * MINSPERHOUR)\n#define SECSPERDAY\t(SECSPERHOUR * HOURSPERDAY)\n#define DAYSPERWEEK\t7\n#define MONSPERYEAR\t12\n\n#define YEAR_BASE\t1900\n#define EPOCH_YEAR      1970\n#define EPOCH_WDAY      4\n#define EPOCH_YEARS_SINCE_LEAP 2\n#define EPOCH_YEARS_SINCE_CENTURY 70\n#define EPOCH_YEARS_SINCE_LEAP_CENTURY 370\n\n#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)\n\nint __tznorth;\nint __tzyear;\nchar reult[100];\nstatic const int mon_lengths[2][12] = {\n  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},\n  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}\n} ;\n\nstatic const int year_lengths[2] = {\n  365,\n  366\n} ;\nstruct tm\n{\n  int\ttm_sec;\n  int\ttm_min;\n  int\ttm_hour;\n  int\ttm_mday;\n  int\ttm_mon;\n  int\ttm_year;\n  int\ttm_wday;\n  int\ttm_yday;\n  int\ttm_isdst;\n};\n\nstruct tm res_buf;\ntypedef struct __tzrule_struct\n{\n  char ch;\n  int m;\n  int n;\n  int d;\n  int s;\n  time_t change;\n  int offset;\n} __tzrule_type;\n\n__tzrule_type sntp__tzrule[2];\nstruct tm * ICACHE_FLASH_ATTR\nsntp_mktm_r(const time_t * tim_p ,struct tm *res ,int is_gmtime)\n{\n  long days, rem;\n  time_t lcltime;\n  int i;\n  int y;\n  int yleap;\n  const int *ip;\n\n  /* base decision about std/dst time on current time */\n  lcltime = *tim_p;\n\n  days = ((long)lcltime) / SECSPERDAY;\n  rem = ((long)lcltime) % SECSPERDAY;\n  while (rem < 0)\n    {\n      rem += SECSPERDAY;\n      --days;\n    }\n  while (rem >= SECSPERDAY)\n    {\n      rem -= SECSPERDAY;\n      ++days;\n    }\n\n  /* compute hour, min, and sec */\n  res->tm_hour = (int) (rem / SECSPERHOUR);\n  rem %= SECSPERHOUR;\n  res->tm_min = (int) (rem / SECSPERMIN);\n  res->tm_sec = (int) (rem % SECSPERMIN);\n\n  /* compute day of week */\n  if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0)\n    res->tm_wday += DAYSPERWEEK;\n\n  /* compute year & day of year */\n  y = EPOCH_YEAR;\n  if (days >= 0)\n    {\n      for (;;)\n\t{\n\t  yleap = isleap(y);\n\t  if (days < year_lengths[yleap])\n\t    break;\n\t  y++;\n\t  days -= year_lengths[yleap];\n\t}\n    }\n  else\n    {\n      do\n\t{\n\t  --y;\n\t  yleap = isleap(y);\n\t  days += year_lengths[yleap];\n\t} while (days < 0);\n    }\n\n  res->tm_year = y - YEAR_BASE;\n  res->tm_yday = days;\n  ip = mon_lengths[yleap];\n  for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon)\n    days -= ip[res->tm_mon];\n  res->tm_mday = days + 1;\n\n  if (!is_gmtime)\n    {\n      int offset;\n      int hours, mins, secs;\n\n//      TZ_LOCK;\n//      if (_daylight)\n//\t{\n//\t  if (y == __tzyear || __tzcalc_limits (y))\n//\t    res->tm_isdst = (__tznorth\n//\t\t\t     ? (*tim_p >= __tzrule[0].change && *tim_p < __tzrule[1].change)\n//\t\t\t     : (*tim_p >= __tzrule[0].change || *tim_p < __tzrule[1].change));\n//\t  else\n//\t    res->tm_isdst = -1;\n//\t}\n//      else\n\tres->tm_isdst = 0;\n\n      offset = (res->tm_isdst == 1 ? sntp__tzrule[1].offset : sntp__tzrule[0].offset);\n\n      hours = offset / SECSPERHOUR;\n      offset = offset % SECSPERHOUR;\n\n      mins = offset / SECSPERMIN;\n      secs = offset % SECSPERMIN;\n\n      res->tm_sec -= secs;\n      res->tm_min -= mins;\n      res->tm_hour -= hours;\n\n      if (res->tm_sec >= SECSPERMIN)\n\t{\n\t  res->tm_min += 1;\n\t  res->tm_sec -= SECSPERMIN;\n\t}\n      else if (res->tm_sec < 0)\n\t{\n\t  res->tm_min -= 1;\n\t  res->tm_sec += SECSPERMIN;\n\t}\n      if (res->tm_min >= MINSPERHOUR)\n\t{\n\t  res->tm_hour += 1;\n\t  res->tm_min -= MINSPERHOUR;\n\t}\n      else if (res->tm_min < 0)\n\t{\n\t  res->tm_hour -= 1;\n\t  res->tm_min += MINSPERHOUR;\n\t}\n      if (res->tm_hour >= HOURSPERDAY)\n\t{\n\t  ++res->tm_yday;\n\t  ++res->tm_wday;\n\t  if (res->tm_wday > 6)\n\t    res->tm_wday = 0;\n\t  ++res->tm_mday;\n\t  res->tm_hour -= HOURSPERDAY;\n\t  if (res->tm_mday > ip[res->tm_mon])\n\t    {\n\t      res->tm_mday -= ip[res->tm_mon];\n\t      res->tm_mon += 1;\n\t      if (res->tm_mon == 12)\n\t\t{\n\t\t  res->tm_mon = 0;\n\t\t  res->tm_year += 1;\n\t\t  res->tm_yday = 0;\n\t\t}\n\t    }\n\t}\n       else if (res->tm_hour < 0)\n\t{\n\t  res->tm_yday -= 1;\n\t  res->tm_wday -= 1;\n\t  if (res->tm_wday < 0)\n\t    res->tm_wday = 6;\n\t  res->tm_mday -= 1;\n\t  res->tm_hour += 24;\n\t  if (res->tm_mday == 0)\n\t    {\n\t      res->tm_mon -= 1;\n\t      if (res->tm_mon < 0)\n\t\t{\n\t\t  res->tm_mon = 11;\n\t\t  res->tm_year -= 1;\n\t\t  res->tm_yday = 365 + isleap(res->tm_year);\n\t\t}\n\t      res->tm_mday = ip[res->tm_mon];\n\t    }\n\t}\n//      TZ_UNLOCK;\n    }\n  else\n    res->tm_isdst = 0;\n//  os_printf(\"res %d %d %d %d %d\\n\",res->tm_year,res->tm_mon,res->tm_mday,res->tm_yday,res->tm_hour);\n  return (res);\n}\nstruct tm * ICACHE_FLASH_ATTR\nsntp_localtime_r(const time_t * tim_p ,\n\t\tstruct tm *res)\n{\n  return sntp_mktm_r (tim_p, res, 0);\n}\n\nstruct tm * ICACHE_FLASH_ATTR\nsntp_localtime(const time_t * tim_p)\n{\n  return sntp_localtime_r (tim_p, &res_buf);\n}\n\n\nint ICACHE_FLASH_ATTR\nsntp__tzcalc_limits(int year)\n{\n  int days, year_days, years;\n  int i, j;\n\n  if (year < EPOCH_YEAR)\n    return 0;\n\n  __tzyear = year;\n\n  years = (year - EPOCH_YEAR);\n\n  year_days = years * 365 +\n    (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 +\n    (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400;\n\n  for (i = 0; i < 2; ++i)\n    {\n      if (sntp__tzrule[i].ch == 'J')\n\tdays = year_days + sntp__tzrule[i].d + (isleap(year) && sntp__tzrule[i].d >= 60);\n      else if (sntp__tzrule[i].ch == 'D')\n\tdays = year_days + sntp__tzrule[i].d;\n      else\n\t{\n\t  int yleap = isleap(year);\n\t  int m_day, m_wday, wday_diff;\n\t  const int *ip = mon_lengths[yleap];\n\n\t  days = year_days;\n\n\t  for (j = 1; j < sntp__tzrule[i].m; ++j)\n\t    days += ip[j-1];\n\n\t  m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK;\n\n\t  wday_diff = sntp__tzrule[i].d - m_wday;\n\t  if (wday_diff < 0)\n\t    wday_diff += DAYSPERWEEK;\n\t  m_day = (sntp__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff;\n\n\t  while (m_day >= ip[j-1])\n\t    m_day -= DAYSPERWEEK;\n\n\t  days += m_day;\n\t}\n\n      /* store the change-over time in GMT form by adding offset */\n      sntp__tzrule[i].change = days * SECSPERDAY + sntp__tzrule[i].s + sntp__tzrule[i].offset;\n    }\n\n  __tznorth = (sntp__tzrule[0].change < sntp__tzrule[1].change);\n\n  return 1;\n}\n\nchar * ICACHE_FLASH_ATTR\nsntp_asctime_r(struct tm *tim_p ,char *result)\n{\n  static const char day_name[7][4] = {\n\t\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"\n  };\n  static const char mon_name[12][4] = {\n\t\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"\n  };\n  os_sprintf (result, \"%s %s %02d %02d:%02d:%02d %02d\\n\",\n\t   day_name[tim_p->tm_wday],\n\t   mon_name[tim_p->tm_mon],\n\t   tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min,\n\t   tim_p->tm_sec, 1900 + tim_p->tm_year);\n  return result;\n}\nchar *ICACHE_FLASH_ATTR\nsntp_asctime(struct tm *tim_p)\n{\n\n    return sntp_asctime_r (tim_p, reult);\n}\n\nuint32 sntp_get_current_timestamp()\n{\n\tif(realtime_stamp == 0){\n\t\tos_printf(\"please start sntp first !\\n\");\n\t\treturn 0;\n\t} else {\n\t\treturn realtime_stamp;\n\t}\n}\n\nchar* sntp_get_real_time(time_t t)\n{\n\treturn sntp_asctime(sntp_localtime (&t));\n}\n/**\n * SNTP get time_zone default GMT + 8\n */\nsint8 ICACHE_FLASH_ATTR\nsntp_get_timezone(void)\n{\n\treturn time_zone;\n}\n/**\n * SNTP set time_zone default GMT + 8\n */\n\nbool ICACHE_FLASH_ATTR\nsntp_set_timezone(sint8 timezone)\n{\n\tif(timezone >= -11 || timezone <= 13) {\n\t\ttime_zone = timezone;\n\t\treturn true;\n\t} else {\n\t\treturn false;\n\t}\n\n}\nvoid ICACHE_FLASH_ATTR\nsntp_time_inc(void)\n{\n\trealtime_stamp++;\n}\n/**\n * SNTP processing of received timestamp\n */\nstatic void ICACHE_FLASH_ATTR\nsntp_process(u32_t *receive_timestamp)\n{\n  /* convert SNTP time (1900-based) to unix GMT time (1970-based)\n   * @todo: if MSB is 1, SNTP time is 2036-based!\n   */\n  time_t t = (ntohl(receive_timestamp[0]) - DIFF_SEC_1900_1970);\n\n#if SNTP_CALC_TIME_US\n  u32_t us = ntohl(receive_timestamp[1]) / 4295;\n  SNTP_SET_SYSTEM_TIME_US(t, us);\n  /* display local time from GMT time */\n  LWIP_DEBUGF(SNTP_DEBUG_TRACE, (\"sntp_process: %s, %\"U32_F\" us\", ctime(&t), us));\n\n#else /* SNTP_CALC_TIME_US */\n\n  /* change system time and/or the update the RTC clock */\n  SNTP_SET_SYSTEM_TIME(t);\n  /* display local time from GMT time */\n  t += time_zone * 60 * 60;// format GMT + time_zone TIME ZONE\n  realtime_stamp = t;\n  os_timer_disarm(&sntp_timer);\n  os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntp_time_inc, NULL);\n  os_timer_arm(&sntp_timer, 1000, 1);\n  os_printf(\"%s\\n\",sntp_asctime(sntp_localtime (&t)));\n//  os_printf(\"%s\\n\",ctime(&t));\n//  LWIP_DEBUGF(SNTP_DEBUG_TRACE, (\"sntp_process: %s\", ctime(&t)));\n#endif /* SNTP_CALC_TIME_US */\n}\n\n/**\n * Initialize request struct to be sent to server.\n */\nstatic void ICACHE_FLASH_ATTR\nsntp_initialize_request(struct sntp_msg *req)\n{\n  os_memset(req, 0, SNTP_MSG_LEN);\n  req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;\n\n#if SNTP_CHECK_RESPONSE >= 2\n  {\n    u32_t sntp_time_sec, sntp_time_us;\n    /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */\n    SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us);\n    sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970);\n    req->transmit_timestamp[0] = sntp_last_timestamp_sent[0];\n    /* we send/save us instead of fraction to be faster... */\n    sntp_last_timestamp_sent[1] = htonl(sntp_time_us);\n    req->transmit_timestamp[1] = sntp_last_timestamp_sent[1];\n  }\n#endif /* SNTP_CHECK_RESPONSE >= 2 */\n}\n\n/**\n * Retry: send a new request (and increase retry timeout).\n *\n * @param arg is unused (only necessary to conform to sys_timeout)\n */\nstatic void ICACHE_FLASH_ATTR\nsntp_retry(void* arg)\n{\n  LWIP_UNUSED_ARG(arg);\n\n  LWIP_DEBUGF(SNTP_DEBUG_STATE, (\"sntp_retry: Next request will be sent in %\"U32_F\" ms\\n\",\n    sntp_retry_timeout));\n\n  /* set up a timer to send a retry and increase the retry delay */\n  sys_timeout(sntp_retry_timeout, sntp_request, NULL);\n\n#if SNTP_RETRY_TIMEOUT_EXP\n  {\n    u32_t new_retry_timeout;\n    /* increase the timeout for next retry */\n    new_retry_timeout = sntp_retry_timeout << 1;\n    /* limit to maximum timeout and prevent overflow */\n    if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) &&\n        (new_retry_timeout > sntp_retry_timeout)) {\n      sntp_retry_timeout = new_retry_timeout;\n    }\n  }\n#endif /* SNTP_RETRY_TIMEOUT_EXP */\n}\n\n#if SNTP_SUPPORT_MULTIPLE_SERVERS\n/**\n * If Kiss-of-Death is received (or another packet parsing error),\n * try the next server or retry the current server and increase the retry\n * timeout if only one server is available.\n * (implicitly, SNTP_MAX_SERVERS > 1)\n *\n * @param arg is unused (only necessary to conform to sys_timeout)\n */\nstatic void\nsntp_try_next_server(void* arg)\n{\n  u8_t old_server, i;\n  LWIP_UNUSED_ARG(arg);\n\n  old_server = sntp_current_server;\n  for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) {\n    sntp_current_server++;\n    if (sntp_current_server >= SNTP_MAX_SERVERS) {\n      sntp_current_server = 0;\n    }\n    if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr)\n#if SNTP_SERVER_DNS\n        || (sntp_servers[sntp_current_server].name != NULL)\n#endif\n        ) {\n      LWIP_DEBUGF(SNTP_DEBUG_STATE, (\"sntp_try_next_server: Sending request to server %\"U16_F\"\\n\",\n        (u16_t)sntp_current_server));\n      /* new server: reset retry timeout */\n      SNTP_RESET_RETRY_TIMEOUT();\n      /* instantly send a request to the next server */\n      sntp_request(NULL);\n      return;\n    }\n  }\n  /* no other valid server found */\n  sntp_current_server = old_server;\n  sntp_retry(NULL);\n}\n#else /* SNTP_SUPPORT_MULTIPLE_SERVERS */\n/* Always retry on error if only one server is supported */\n#define sntp_try_next_server    sntp_retry\n#endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */\n\n/** UDP recv callback for the sntp pcb */\nstatic void ICACHE_FLASH_ATTR\nsntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)\n{\n  u8_t mode;\n  u8_t stratum;\n  u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE];\n  err_t err;\n//os_printf(\"sntp_recv\\n\");\n  LWIP_UNUSED_ARG(arg);\n  LWIP_UNUSED_ARG(pcb);\n\n  /* packet received: stop retry timeout  */\n  sys_untimeout(sntp_try_next_server, NULL);\n  sys_untimeout(sntp_request, NULL);\n\n  err = ERR_ARG;\n#if SNTP_CHECK_RESPONSE >= 1\n  /* check server address and port */\n  if (ip_addr_cmp(addr, &sntp_last_server_address) &&\n    (port == SNTP_PORT))\n#else /* SNTP_CHECK_RESPONSE >= 1 */\n  LWIP_UNUSED_ARG(addr);\n  LWIP_UNUSED_ARG(port);\n#endif /* SNTP_CHECK_RESPONSE >= 1 */\n  {\n    /* process the response */\n    if (p->tot_len == SNTP_MSG_LEN) {\n      pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE);\n      mode &= SNTP_MODE_MASK;\n      /* if this is a SNTP response... */\n      if ((mode == SNTP_MODE_SERVER) ||\n          (mode == SNTP_MODE_BROADCAST)) {\n        pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM);\n        if (stratum == SNTP_STRATUM_KOD) {\n          /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */\n          err = SNTP_ERR_KOD;\n          LWIP_DEBUGF(SNTP_DEBUG_STATE, (\"sntp_recv: Received Kiss-of-Death\\n\"));\n        } else {\n#if SNTP_CHECK_RESPONSE >= 2\n          /* check originate_timetamp against sntp_last_timestamp_sent */\n          u32_t originate_timestamp[2];\n          pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME);\n          if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) ||\n              (originate_timestamp[1] != sntp_last_timestamp_sent[1]))\n          {\n            LWIP_DEBUGF(SNTP_DEBUG_WARN, (\"sntp_recv: Invalid originate timestamp in response\\n\"));\n          } else\n#endif /* SNTP_CHECK_RESPONSE >= 2 */\n          /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */\n          {\n            /* correct answer */\n            err = ERR_OK;\n            pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_RECEIVE_TIME);\n          }\n        }\n      } else {\n        LWIP_DEBUGF(SNTP_DEBUG_WARN, (\"sntp_recv: Invalid mode in response: %\"U16_F\"\\n\", (u16_t)mode));\n      }\n    } else {\n      LWIP_DEBUGF(SNTP_DEBUG_WARN, (\"sntp_recv: Invalid packet length: %\"U16_F\"\\n\", p->tot_len));\n    }\n  }\n  pbuf_free(p);\n  if (err == ERR_OK) {\n    /* Correct response, reset retry timeout */\n    SNTP_RESET_RETRY_TIMEOUT();\n\n    sntp_process(receive_timestamp);\n\n    /* Set up timeout for next request */\n    sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL);\n    LWIP_DEBUGF(SNTP_DEBUG_STATE, (\"sntp_recv: Scheduled next time request: %\"U32_F\" ms\\n\",\n      (u32_t)SNTP_UPDATE_DELAY));\n  } else if (err == SNTP_ERR_KOD) {\n    /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */\n    sntp_try_next_server(NULL);\n  } else {\n    /* another error, try the same server again */\n    sntp_retry(NULL);\n  }\n}\n\n/** Actually send an sntp request to a server.\n *\n * @param server_addr resolved IP address of the SNTP server\n */\nstatic void ICACHE_FLASH_ATTR\nsntp_send_request(ip_addr_t *server_addr)\n{\n  struct pbuf* p;\n//  os_printf(\"sntp_send_request\\n\");\n  p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);\n  if (p != NULL) {\n    struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload;\n    LWIP_DEBUGF(SNTP_DEBUG_STATE, (\"sntp_send_request: Sending request to server\\n\"));\n    /* initialize request message */\n    sntp_initialize_request(sntpmsg);\n    /* send request */\n    udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT);\n    /* free the pbuf after sending it */\n    pbuf_free(p);\n    /* set up receive timeout: try next server or retry on timeout */\n    sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);\n#if SNTP_CHECK_RESPONSE >= 1\n    /* save server address to verify it in sntp_recv */ \n    ip_addr_set(&sntp_last_server_address, server_addr);\n#endif /* SNTP_CHECK_RESPONSE >= 1 */\n  } else {\n    LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, (\"sntp_send_request: Out of memory, trying again in %\"U32_F\" ms\\n\",\n      (u32_t)SNTP_RETRY_TIMEOUT));\n    /* out of memory: set up a timer to send a retry */\n    sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL);\n  }\n}\n\n#if SNTP_SERVER_DNS\n/**\n * DNS found callback when using DNS names as server address.\n */\nstatic void\nsntp_dns_found(const char* hostname, ip_addr_t *ipaddr, void *arg)\n{\n  LWIP_UNUSED_ARG(hostname);\n  LWIP_UNUSED_ARG(arg);\n\n  if (ipaddr != NULL) {\n    /* Address resolved, send request */\n    LWIP_DEBUGF(SNTP_DEBUG_STATE, (\"sntp_dns_found: Server address resolved, sending request\\n\"));\n    sntp_send_request(ipaddr);\n  } else {\n    /* DNS resolving failed -> try another server */\n    LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, (\"sntp_dns_found: Failed to resolve server address resolved, trying next server\\n\"));\n    sntp_try_next_server(NULL);\n  }\n}\n#endif /* SNTP_SERVER_DNS */\n\n/**\n * Send out an sntp request.\n *\n * @param arg is unused (only necessary to conform to sys_timeout)\n */\nstatic void ICACHE_FLASH_ATTR\nsntp_request(void *arg)\n{\n  ip_addr_t sntp_server_address;\n  err_t err;\n\n  LWIP_UNUSED_ARG(arg);\n\n  /* initialize SNTP server address */\n#if SNTP_SERVER_DNS\n\n  if (sntp_servers[sntp_current_server].name) {\n    /* always resolve the name and rely on dns-internal caching & timeout */\n    ip_addr_set_any(&sntp_servers[sntp_current_server].addr);\n    err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address,\n      sntp_dns_found, NULL);\n    if (err == ERR_INPROGRESS) {\n      /* DNS request sent, wait for sntp_dns_found being called */\n      LWIP_DEBUGF(SNTP_DEBUG_STATE, (\"sntp_request: Waiting for server address to be resolved.\\n\"));\n      return;\n    } else if (err == ERR_OK) {\n      sntp_servers[sntp_current_server].addr = sntp_server_address;\n    }\n  } else\n#endif /* SNTP_SERVER_DNS */\n  {\n    sntp_server_address = sntp_servers[sntp_current_server].addr;\n//    os_printf(\"sntp_server_address ip %d\\n\",sntp_server_address.addr);\n    err = (ip_addr_isany(&sntp_server_address)) ? ERR_ARG : ERR_OK;\n  }\n\n  if (err == ERR_OK) {\n    LWIP_DEBUGF(SNTP_DEBUG_TRACE, (\"sntp_request: current server address is %u.%u.%u.%u\\n\",\n      ip4_addr1(&sntp_server_address), ip4_addr2(&sntp_server_address), ip4_addr3(&sntp_server_address), ip4_addr4(&sntp_server_address)));\n    sntp_send_request(&sntp_server_address);\n  } else {\n    /* address conversion failed, try another server */\n    LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, (\"sntp_request: Invalid server address, trying next server.\\n\"));\n    sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL);\n  }\n}\n\n/**\n * Initialize this module.\n * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).\n */\nvoid ICACHE_FLASH_ATTR\nsntp_init(void)\n{\n#ifdef SNTP_SERVER_ADDRESS\n#if SNTP_SERVER_DNS\n  sntp_setservername(0, SNTP_SERVER_ADDRESS);\n#else\n#error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0\n#endif\n#endif /* SNTP_SERVER_ADDRESS */\n\n  if (sntp_pcb == NULL) {\n    SNTP_RESET_RETRY_TIMEOUT();\n    sntp_pcb = udp_new();\n    LWIP_ASSERT(\"Failed to allocate udp pcb for sntp client\", sntp_pcb != NULL);\n    if (sntp_pcb != NULL) {\n      udp_recv(sntp_pcb, sntp_recv, NULL);\n#if SNTP_STARTUP_DELAY\n      sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL);\n#else\n      sntp_request(NULL);\n#endif\n    }\n  }\n}\n\n/**\n * Stop this module.\n */\nvoid ICACHE_FLASH_ATTR\nsntp_stop(void)\n{\n  if (sntp_pcb != NULL) {\n    sys_untimeout(sntp_request, NULL);\n    udp_remove(sntp_pcb);\n    sntp_pcb = NULL;\n  }\n  os_timer_disarm(&sntp_timer);\n  realtime_stamp = 0;\n}\n\n#if SNTP_GET_SERVERS_FROM_DHCP\n/**\n * Config SNTP server handling by IP address, name, or DHCP; clear table\n * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp\n */\nvoid\nsntp_servermode_dhcp(int set_servers_from_dhcp)\n{\n  u8_t new_mode = set_servers_from_dhcp ? 1 : 0;\n  if (sntp_set_servers_from_dhcp != new_mode) {\n    sntp_set_servers_from_dhcp = new_mode;\n  }\n}\n#endif /* SNTP_GET_SERVERS_FROM_DHCP */\n\n/**\n * Initialize one of the NTP servers by IP address\n *\n * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS\n * @param dnsserver IP address of the NTP server to set\n */\nvoid ICACHE_FLASH_ATTR\nsntp_setserver(u8_t idx, ip_addr_t *server)\n{\n  if (idx < SNTP_MAX_SERVERS) {\n    if (server != NULL) {\n      sntp_servers[idx].addr = (*server);\n//      os_printf(\"server ip %d\\n\",server->addr);\n    } else {\n      ip_addr_set_any(&sntp_servers[idx].addr);\n    }\n#if SNTP_SERVER_DNS\n    sntp_servers[idx].name = NULL;\n#endif\n  }\n}\n\n#if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP\n/**\n * Initialize one of the NTP servers by IP address, required by DHCP\n *\n * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS\n * @param dnsserver IP address of the NTP server to set\n */\nvoid\ndhcp_set_ntp_servers(u8_t num, ip_addr_t *server)\n{\n  LWIP_DEBUGF(SNTP_DEBUG_TRACE, (\"sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\\n\",\n    (sntp_set_servers_from_dhcp ? \"Got\" : \"Rejected\"),\n    ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num));\n  if (sntp_set_servers_from_dhcp && num) {\n    u8_t i;\n    for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) {\n      sntp_setserver(i, &server[i]);\n    }\n    for (i = num; i < SNTP_MAX_SERVERS; i++) {\n      sntp_setserver(i, NULL);\n    }\n  }\n}\n#endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */\n\n/**\n * Obtain one of the currently configured by IP address (or DHCP) NTP servers \n *\n * @param numdns the index of the NTP server\n * @return IP address of the indexed NTP server or \"ip_addr_any\" if the NTP\n *         server has not been configured by address (or at all).\n */\nip_addr_t ICACHE_FLASH_ATTR\nsntp_getserver(u8_t idx)\n{\n  if (idx < SNTP_MAX_SERVERS) {\n    return sntp_servers[idx].addr;\n  }\n  return *IP_ADDR_ANY;\n}\n\n#if SNTP_SERVER_DNS\n/**\n * Initialize one of the NTP servers by name\n *\n * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS\n * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time\n */\nvoid ICACHE_FLASH_ATTR\nsntp_setservername(u8_t idx, char *server)\n{\n  if (idx < SNTP_MAX_SERVERS) {\n    sntp_servers[idx].name = server;\n  }\n}\n\n/**\n * Obtain one of the currently configured by name NTP servers.\n *\n * @param numdns the index of the NTP server\n * @return IP address of the indexed NTP server or NULL if the NTP\n *         server has not been configured by name (or at all)\n */\nchar * ICACHE_FLASH_ATTR\nsntp_getservername(u8_t idx)\n{\n  if (idx < SNTP_MAX_SERVERS) {\n    return sntp_servers[idx].name;\n  }\n  return NULL;\n}\n#endif /* SNTP_SERVER_DNS */\n\n#endif /* LWIP_UDP */\n"
  },
  {
    "path": "app/lwip/core/stats.c",
    "content": "/**\n * @file\n * Statistics module\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/def.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/mem.h\"\n\n#include <string.h>\n\nstruct stats_ lwip_stats;\n\nvoid stats_init(void)\n{\n#ifdef LWIP_DEBUG\n#if MEMP_STATS\n  const char * memp_names[] = {\n#define LWIP_MEMPOOL(name,num,size,desc) desc,\n#include \"lwip/memp_std.h\"\n  };\n  int i;\n  for (i = 0; i < MEMP_MAX; i++) {\n    lwip_stats.memp[i].name = memp_names[i];\n  }\n#endif /* MEMP_STATS */\n#if MEM_STATS\n  lwip_stats.mem.name = \"MEM\";\n#endif /* MEM_STATS */\n#endif /* LWIP_DEBUG */\n}\n\n#if LWIP_STATS_DISPLAY\nvoid\nstats_display_proto(struct stats_proto *proto, char *name)\n{\n  LWIP_PLATFORM_DIAG((\"\\n%s\\n\\t\", name));\n  LWIP_PLATFORM_DIAG((\"xmit: %\"STAT_COUNTER_F\"\\n\\t\", proto->xmit)); \n  LWIP_PLATFORM_DIAG((\"recv: %\"STAT_COUNTER_F\"\\n\\t\", proto->recv)); \n  LWIP_PLATFORM_DIAG((\"fw: %\"STAT_COUNTER_F\"\\n\\t\", proto->fw)); \n  LWIP_PLATFORM_DIAG((\"drop: %\"STAT_COUNTER_F\"\\n\\t\", proto->drop)); \n  LWIP_PLATFORM_DIAG((\"chkerr: %\"STAT_COUNTER_F\"\\n\\t\", proto->chkerr)); \n  LWIP_PLATFORM_DIAG((\"lenerr: %\"STAT_COUNTER_F\"\\n\\t\", proto->lenerr)); \n  LWIP_PLATFORM_DIAG((\"memerr: %\"STAT_COUNTER_F\"\\n\\t\", proto->memerr)); \n  LWIP_PLATFORM_DIAG((\"rterr: %\"STAT_COUNTER_F\"\\n\\t\", proto->rterr)); \n  LWIP_PLATFORM_DIAG((\"proterr: %\"STAT_COUNTER_F\"\\n\\t\", proto->proterr)); \n  LWIP_PLATFORM_DIAG((\"opterr: %\"STAT_COUNTER_F\"\\n\\t\", proto->opterr)); \n  LWIP_PLATFORM_DIAG((\"err: %\"STAT_COUNTER_F\"\\n\\t\", proto->err)); \n  LWIP_PLATFORM_DIAG((\"cachehit: %\"STAT_COUNTER_F\"\\n\", proto->cachehit)); \n}\n\n#if IGMP_STATS\nvoid\nstats_display_igmp(struct stats_igmp *igmp)\n{\n  LWIP_PLATFORM_DIAG((\"\\nIGMP\\n\\t\"));\n  LWIP_PLATFORM_DIAG((\"xmit: %\"STAT_COUNTER_F\"\\n\\t\", igmp->xmit)); \n  LWIP_PLATFORM_DIAG((\"recv: %\"STAT_COUNTER_F\"\\n\\t\", igmp->recv)); \n  LWIP_PLATFORM_DIAG((\"drop: %\"STAT_COUNTER_F\"\\n\\t\", igmp->drop)); \n  LWIP_PLATFORM_DIAG((\"chkerr: %\"STAT_COUNTER_F\"\\n\\t\", igmp->chkerr)); \n  LWIP_PLATFORM_DIAG((\"lenerr: %\"STAT_COUNTER_F\"\\n\\t\", igmp->lenerr)); \n  LWIP_PLATFORM_DIAG((\"memerr: %\"STAT_COUNTER_F\"\\n\\t\", igmp->memerr)); \n  LWIP_PLATFORM_DIAG((\"proterr: %\"STAT_COUNTER_F\"\\n\\t\", igmp->proterr)); \n  LWIP_PLATFORM_DIAG((\"rx_v1: %\"STAT_COUNTER_F\"\\n\\t\", igmp->rx_v1)); \n  LWIP_PLATFORM_DIAG((\"rx_group: %\"STAT_COUNTER_F\"\\n\", igmp->rx_group));\n  LWIP_PLATFORM_DIAG((\"rx_general: %\"STAT_COUNTER_F\"\\n\", igmp->rx_general));\n  LWIP_PLATFORM_DIAG((\"rx_report: %\"STAT_COUNTER_F\"\\n\\t\", igmp->rx_report)); \n  LWIP_PLATFORM_DIAG((\"tx_join: %\"STAT_COUNTER_F\"\\n\\t\", igmp->tx_join)); \n  LWIP_PLATFORM_DIAG((\"tx_leave: %\"STAT_COUNTER_F\"\\n\\t\", igmp->tx_leave)); \n  LWIP_PLATFORM_DIAG((\"tx_report: %\"STAT_COUNTER_F\"\\n\\t\", igmp->tx_report)); \n}\n#endif /* IGMP_STATS */\n\n#if MEM_STATS || MEMP_STATS\nvoid\nstats_display_mem(struct stats_mem *mem, char *name)\n{\n  LWIP_PLATFORM_DIAG((\"\\nMEM %s\\n\\t\", name));\n  LWIP_PLATFORM_DIAG((\"avail: %\"U32_F\"\\n\\t\", (u32_t)mem->avail)); \n  LWIP_PLATFORM_DIAG((\"used: %\"U32_F\"\\n\\t\", (u32_t)mem->used)); \n  LWIP_PLATFORM_DIAG((\"max: %\"U32_F\"\\n\\t\", (u32_t)mem->max)); \n  LWIP_PLATFORM_DIAG((\"err: %\"U32_F\"\\n\", (u32_t)mem->err));\n}\n\n#if MEMP_STATS\nvoid\nstats_display_memp(struct stats_mem *mem, int index)\n{\n  char * memp_names[] = {\n#define LWIP_MEMPOOL(name,num,size,desc) desc,\n#include \"lwip/memp_std.h\"\n  };\n  if(index < MEMP_MAX) {\n    stats_display_mem(mem, memp_names[index]);\n  }\n}\n#endif /* MEMP_STATS */\n#endif /* MEM_STATS || MEMP_STATS */\n\n#if SYS_STATS\nvoid\nstats_display_sys(struct stats_sys *sys)\n{\n  LWIP_PLATFORM_DIAG((\"\\nSYS\\n\\t\"));\n  LWIP_PLATFORM_DIAG((\"sem.used:  %\"U32_F\"\\n\\t\", (u32_t)sys->sem.used)); \n  LWIP_PLATFORM_DIAG((\"sem.max:   %\"U32_F\"\\n\\t\", (u32_t)sys->sem.max)); \n  LWIP_PLATFORM_DIAG((\"sem.err:   %\"U32_F\"\\n\\t\", (u32_t)sys->sem.err)); \n  LWIP_PLATFORM_DIAG((\"mutex.used: %\"U32_F\"\\n\\t\", (u32_t)sys->mutex.used)); \n  LWIP_PLATFORM_DIAG((\"mutex.max:  %\"U32_F\"\\n\\t\", (u32_t)sys->mutex.max)); \n  LWIP_PLATFORM_DIAG((\"mutex.err:  %\"U32_F\"\\n\\t\", (u32_t)sys->mutex.err)); \n  LWIP_PLATFORM_DIAG((\"mbox.used:  %\"U32_F\"\\n\\t\", (u32_t)sys->mbox.used)); \n  LWIP_PLATFORM_DIAG((\"mbox.max:   %\"U32_F\"\\n\\t\", (u32_t)sys->mbox.max)); \n  LWIP_PLATFORM_DIAG((\"mbox.err:   %\"U32_F\"\\n\\t\", (u32_t)sys->mbox.err)); \n}\n#endif /* SYS_STATS */\n\nvoid\nstats_display(void)\n{\n  s16_t i;\n\n  LINK_STATS_DISPLAY();\n  ETHARP_STATS_DISPLAY();\n  IPFRAG_STATS_DISPLAY();\n  IP_STATS_DISPLAY();\n  IGMP_STATS_DISPLAY();\n  ICMP_STATS_DISPLAY();\n  UDP_STATS_DISPLAY();\n  TCP_STATS_DISPLAY();\n  MEM_STATS_DISPLAY();\n  for (i = 0; i < MEMP_MAX; i++) {\n    MEMP_STATS_DISPLAY(i);\n  }\n  SYS_STATS_DISPLAY();\n}\n#endif /* LWIP_STATS_DISPLAY */\n\n#endif /* LWIP_STATS */\n\n"
  },
  {
    "path": "app/lwip/core/sys.c",
    "content": "/**\n * @file\n * lwIP Operating System abstraction\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/sys.h\"\n\n/* Most of the functions defined in sys.h must be implemented in the\n * architecture-dependent file sys_arch.c */\n\n#if !NO_SYS\n\n/**\n * Sleep for some ms. Timeouts are NOT processed while sleeping.\n *\n * @param ms number of milliseconds to sleep\n */\nvoid\nsys_msleep(u32_t ms)\n{\n  if (ms > 0) {\n    sys_sem_t delaysem;\n    err_t err = sys_sem_new(&delaysem, 0);\n    if (err == ERR_OK) {\n      sys_arch_sem_wait(&delaysem, ms);\n      sys_sem_free(&delaysem);\n    }\n  }\n}\n\n#endif /* !NO_SYS */\n"
  },
  {
    "path": "app/lwip/core/sys_arch.c",
    "content": "/*\r\n * copyright (c) 2010 - 2011 espressif system\r\n */\r\n\r\n#include \"c_types.h\"\r\n#include \"ets_sys.h\"\r\n#include \"osapi.h\"\r\n#include \"os_type.h\"\r\n\r\n#include \"lwip/opt.h\"\r\n#include \"lwip/sys.h\"\r\n\r\n#include \"eagle_soc.h\"\r\n"
  },
  {
    "path": "app/lwip/core/tcp.c",
    "content": "/**\n * @file\n * Transmission Control Protocol for IP\n *\n * This file contains common functions for the TCP implementation, such as functinos\n * for manipulating the data structures and the TCP timer functions. TCP functions\n * related to input and output is found in tcp_in.c and tcp_out.c respectively.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved. \n * \n * Redistribution and use in source and binary forms, with or without modification, \n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission. \n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n * \n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/def.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/snmp.h\"\n#include \"lwip/tcp.h\"\n#include \"lwip/tcp_impl.h\"\n#include \"lwip/debug.h\"\n#include \"lwip/stats.h\"\n\n#include <string.h>\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n#if TCP_DEBUG\nconst char tcp_state_str_rodata[][12] ICACHE_RODATA_ATTR = {\n  \"CLOSED\",      \n  \"LISTEN\",      \n  \"SYN_SENT\",    \n  \"SYN_RCVD\",    \n  \"ESTABLISHED\", \n  \"FIN_WAIT_1\",  \n  \"FIN_WAIT_2\",  \n  \"CLOSE_WAIT\",  \n  \"CLOSING\",     \n  \"LAST_ACK\",    \n  \"TIME_WAIT\"   \n};\n\nchar tcp_state_str[12];\n#endif\n\n/* Incremented every coarse grained timer shot (typically every 500 ms). */\nu32_t tcp_ticks;\nconst u8_t tcp_backoff[13] ICACHE_RODATA_ATTR =\n    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};\n /* Times per slowtmr hits */\nconst u8_t tcp_persist_backoff[7] ICACHE_RODATA_ATTR = { 3, 6, 12, 24, 48, 96, 120 };\n\n/* The TCP PCB lists. */\n\n/** List of all TCP PCBs bound but not yet (connected || listening) */\nstruct tcp_pcb *tcp_bound_pcbs;\n/** List of all TCP PCBs in LISTEN state */\nunion tcp_listen_pcbs_t tcp_listen_pcbs;\n/** List of all TCP PCBs that are in a state in which\n * they accept or send data. */\nstruct tcp_pcb *tcp_active_pcbs;\n/** List of all TCP PCBs in TIME-WAIT state */\nstruct tcp_pcb *tcp_tw_pcbs;\n\n#define NUM_TCP_PCB_LISTS               4\n#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT  3\n/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */\nstruct tcp_pcb ** const tcp_pcb_lists[] ICACHE_RODATA_ATTR = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,\n  &tcp_active_pcbs, &tcp_tw_pcbs};\n\n/** Only used for temporary storage. */\nstruct tcp_pcb *tcp_tmp_pcb;\n\n/** Timer counter to handle calling slow-timer from tcp_tmr() */ \nstatic u8_t tcp_timer;\nstatic u16_t tcp_new_port(void);//����µ�tcp���ض˿�\n\n/**\n * Called periodically to dispatch TCP timers.\n *\n */\nvoid\ntcp_tmr(void)\n{\n  /* Call tcp_fasttmr() every 250 ms */\n  tcp_fasttmr();\n\n  if (++tcp_timer & 1) {\n    /* Call tcp_tmr() every 500 ms, i.e., every other timer\n       tcp_tmr() is called. */\n    tcp_slowtmr();\n  }\n}\n\n/**\n * Closes the TX side of a connection held by the PCB.\n * For tcp_close(), a RST is sent if the application didn't receive all data\n * (tcp_recved() not called for all data passed to recv callback).\n *\n * Listening pcbs are freed and may not be referenced any more.\n * Connection pcbs are freed if not yet connected and may not be referenced\n * any more. If a connection is established (at least SYN received or in\n * a closing state), the connection is closed, and put in a closing state.\n * The pcb is then automatically freed in tcp_slowtmr(). It is therefore\n * unsafe to reference it.\n *\n * @param pcb the tcp_pcb to close\n * @return ERR_OK if connection has been closed\n *         another err_t if closing failed and pcb is not freed\n */\nstatic err_t\ntcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)\n{\n  err_t err;\n\n  if (rst_on_unacked_data && (pcb->state != LISTEN)) {\n    if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) {\n      /* Not all data received by application, send RST to tell the remote\n         side about this. */\n      LWIP_ASSERT(\"pcb->flags & TF_RXCLOSED\", pcb->flags & TF_RXCLOSED);\n\n      /* don't call tcp_abort here: we must not deallocate the pcb since\n         that might not be expected when calling tcp_close */\n      tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,\n        pcb->local_port, pcb->remote_port);\n\n      tcp_pcb_purge(pcb);\n\n      /* TODO: to which state do we move now? */\n\n      /* move to TIME_WAIT since we close actively */\n      TCP_RMV(&tcp_active_pcbs, pcb);\n      pcb->state = TIME_WAIT;\n      TCP_REG(&tcp_tw_pcbs, pcb);\n\n      return ERR_OK;\n    }\n  }\n\n  switch (pcb->state) {\n  case CLOSED:\n    /* Closing a pcb in the CLOSED state might seem erroneous,\n     * however, it is in this state once allocated and as yet unused\n     * and the user needs some way to free it should the need arise.\n     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)\n     * or for a pcb that has been used and then entered the CLOSED state \n     * is erroneous, but this should never happen as the pcb has in those cases\n     * been freed, and so any remaining handles are bogus. */\n     /*��CLOSED״̬�¹ر�һ��pcb�ƺ��Ǵ���ģ� \n     *������ˣ�һ�������״̬�·����˶��һ�û��ʹ��,�û���ҪһЩ�취���ͷ��� \n     *����һ���Ѿ����رյ�pcb��tcp_close(),(��2��)����һ���Ѿ���ʹ����֮�󣬽���CLOSE״̬�Ǵ���� \n     *������Щ����±��ͷŵ�pcb�ǲ�����ڵ�,��ˣ��κ�ʣ��ľ���Ǽٵ� \n     */  \n    err = ERR_OK;//�趨����ֵ \n    if (pcb->local_port != 0) {\n    \tTCP_RMV(&tcp_bound_pcbs, pcb); \n    }\n    memp_free(MEMP_TCP_PCB, pcb);//��MEMP_TCP_PCB�ڴ���趨�ͷŵ���pcb��Ӧ�ĵ�Ԫֵ,�ͷ��ڴ�\n    pcb = NULL;\n    break;\n  case LISTEN:\n    err = ERR_OK;\n    tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);//�Ӽ����PCB�б���ɾ���Ӧ��pcb  \n    memp_free(MEMP_TCP_PCB_LISTEN, pcb);//��MEMP_TCP_PCB_LISTEN�ڴ�����趨�ͷŵ�pcb��Ԫֵ  ,�ͷ��ڴ�\n    pcb = NULL;\n    break;\n  case SYN_SENT:\n    err = ERR_OK;\n    tcp_pcb_remove(&tcp_active_pcbs, pcb);\n    memp_free(MEMP_TCP_PCB, pcb);\n    pcb = NULL;\n    snmp_inc_tcpattemptfails();\n    break;\n  case SYN_RCVD:\n    err = tcp_send_fin(pcb);//���������ر�FIN���ֱ���\n    if (err == ERR_OK) {\n      snmp_inc_tcpattemptfails();\n      pcb->state = FIN_WAIT_1;//ת��FIN_WAIT_1״̬\n    }\n    break;\n  case ESTABLISHED:\n    err = tcp_send_fin(pcb);\n    if (err == ERR_OK) {\n      snmp_inc_tcpestabresets();\n      pcb->state = FIN_WAIT_1;\n    }\n    break;\n  case CLOSE_WAIT:\n    err = tcp_send_fin(pcb);\n    if (err == ERR_OK) {\n      snmp_inc_tcpestabresets();\n      pcb->state = LAST_ACK;//����LAST_ACK�ȴ�ACK��ʱ\n    }\n    break;\n  default:\n    /* Has already been closed, do nothing. */\n    err = ERR_OK;\n    pcb = NULL;\n    break;\n  }\n\n  if (pcb != NULL && err == ERR_OK) {\n    /* To ensure all data has been sent when tcp_close returns, we have\n       to make sure tcp_output doesn't fail.\n       Since we don't really have to ensure all data has been sent when tcp_close\n       returns (unsent data is sent from tcp timer functions, also), we don't care\n       for the return value of tcp_output for now. */\n    /* @todo: When implementing SO_LINGER, this must be changed somehow:\n       If SOF_LINGER is set, the data should be sent and acked before close returns.\n       This can only be valid for sequential APIs, not for the raw API. */\n    tcp_output(pcb);//���ú����Ϳ��ƿ������ʣ��ı��ģ�����FIN���ֱ��Ķ�\n  }\n  return err;\n}\n\n/**\n * Closes the connection held by the PCB.\n *\n * Listening pcbs are freed and may not be referenced any more.\n * Connection pcbs are freed if not yet connected and may not be referenced\n * any more. If a connection is established (at least SYN received or in\n * a closing state), the connection is closed, and put in a closing state.\n * The pcb is then automatically freed in tcp_slowtmr(). It is therefore\n * unsafe to reference it (unless an error is returned).\n *\n * @param pcb the tcp_pcb to close\n * @return ERR_OK if connection has been closed\n *         another err_t if closing failed and pcb is not freed\n */\n /* \n *ͨ��PCB�ر��������� \n *�����е�pcbӦ�ñ��ͷŵģ�Ҳ����ԶҲ���ᱻʹ���� \n *���û�����ӻ�����Ҳû�б�����,���ӵ�pcbӦ�ñ��ͷŵ� \n *���һ�����ӱ�����(����SYN�Ѿ������ջ�����һ���ر��е�״̬) \n *���ӱ��ر��ˣ�����������һ�����ڹرյ�״̬ \n *pcb�Զ���tcp_slowtmr()�ͷ�,�����������ǲ���ȫ�� \n */ \nerr_t\ntcp_close(struct tcp_pcb *pcb)\n{\n#if TCP_DEBUG\t//TCP debug��Ϣ����ӡpcb��״̬\n  LWIP_DEBUGF(TCP_DEBUG, (\"tcp_close: closing in \"));\n  tcp_debug_print_state(pcb->state);\n#endif /* TCP_DEBUG */\n\n  if (pcb->state != LISTEN) {\n    /* Set a flag not to receive any more data... */\n    pcb->flags |= TF_RXCLOSED;\n  }\n  /* ... and close */\n  return tcp_close_shutdown(pcb, 1);\n}\n\n/**\n * Causes all or part of a full-duplex connection of this PCB to be shut down.\n * This doesn't deallocate the PCB!\n *\n * @param pcb PCB to shutdown\n * @param shut_rx shut down receive side if this is != 0\n * @param shut_tx shut down send side if this is != 0\n * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down)\n *         another err_t on error.\n */\nerr_t\ntcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)\n{\n  if (pcb->state == LISTEN) {\n    return ERR_CONN;\n  }\n  if (shut_rx) {\n    /* shut down the receive side: free buffered data... */\n    if (pcb->refused_data != NULL) {\n      pbuf_free(pcb->refused_data);\n      pcb->refused_data = NULL;\n    }\n    /* ... and set a flag not to receive any more data */\n    pcb->flags |= TF_RXCLOSED;\n  }\n  if (shut_tx) {\n    /* This can't happen twice since if it succeeds, the pcb's state is changed.\n       Only close in these states as the others directly deallocate the PCB */\n    switch (pcb->state) {\n  case SYN_RCVD:\n  case ESTABLISHED:\n  case CLOSE_WAIT:\n    return tcp_close_shutdown(pcb, 0);\n  default:\n    /* don't shut down other states */\n    break;\n    }\n  }\n  /* @todo: return another err_t if not in correct state or already shut? */\n  return ERR_OK;\n}\n\n/**\n * Abandons a connection and optionally sends a RST to the remote\n * host.  Deletes the local protocol control block. This is done when\n * a connection is killed because of shortage of memory.\n *\n * @param pcb the tcp_pcb to abort\n * @param reset boolean to indicate whether a reset should be sent\n */\nvoid\ntcp_abandon(struct tcp_pcb *pcb, int reset)\n{\n  u32_t seqno, ackno;\n  u16_t remote_port, local_port;\n  ip_addr_t remote_ip, local_ip;\n#if LWIP_CALLBACK_API  \n  tcp_err_fn errf;\n#endif /* LWIP_CALLBACK_API */\n  void *errf_arg;\n\n  /* pcb->state LISTEN not allowed here */\n  LWIP_ASSERT(\"don't call tcp_abort/tcp_abandon for listen-pcbs\",\n    pcb->state != LISTEN);\n  /* Figure out on which TCP PCB list we are, and remove us. If we\n     are in an active state, call the receive function associated with\n     the PCB with a NULL argument, and send an RST to the remote end. */\n  if (pcb->state == TIME_WAIT) {\n    tcp_pcb_remove(&tcp_tw_pcbs, pcb);\n    memp_free(MEMP_TCP_PCB, pcb);\n  } else {\n    seqno = pcb->snd_nxt;\n    ackno = pcb->rcv_nxt;\n    ip_addr_copy(local_ip, pcb->local_ip);\n    ip_addr_copy(remote_ip, pcb->remote_ip);\n    local_port = pcb->local_port;\n    remote_port = pcb->remote_port;\n#if LWIP_CALLBACK_API\n    errf = pcb->errf;\n#endif /* LWIP_CALLBACK_API */\n    errf_arg = pcb->callback_arg;\n    tcp_pcb_remove(&tcp_active_pcbs, pcb);\n    if (pcb->unacked != NULL) {\n      tcp_segs_free(pcb->unacked);\n    }\n    if (pcb->unsent != NULL) {\n      tcp_segs_free(pcb->unsent);\n    }\n#if TCP_QUEUE_OOSEQ    \n    if (pcb->ooseq != NULL) {\n      tcp_segs_free(pcb->ooseq);\n    }\n#endif /* TCP_QUEUE_OOSEQ */\n    if (reset) {\n      LWIP_DEBUGF(TCP_RST_DEBUG, (\"tcp_abandon: sending RST\\n\"));\n      tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);\n    }\n\tTCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);\n\tmemp_free(MEMP_TCP_PCB, pcb);\n  }\n}\n\n/**\n * Aborts the connection by sending a RST (reset) segment to the remote\n * host. The pcb is deallocated. This function never fails.\n *\n * ATTENTION: When calling this from one of the TCP callbacks, make\n * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise\n * or you will risk accessing deallocated memory or memory leaks!\n *\n * @param pcb the tcp pcb to abort\n */\nvoid\ntcp_abort(struct tcp_pcb *pcb)\n{\n  tcp_abandon(pcb, 1);\n}\n\n/**\n * Binds the connection to a local portnumber and IP address. If the\n * IP address is not given (i.e., ipaddr == NULL), the IP address of\n * the outgoing network interface is used instead.\n *\n * @param pcb the tcp_pcb to bind (no check is done whether this pcb is\n *        already bound!)\n * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind\n *        to any local address\n * @param port the local port to bind to\n * @return ERR_USE if the port is already in use\n *         ERR_OK if bound\n */\nerr_t\ntcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)\n{\n  int i;\n  int max_pcb_list = NUM_TCP_PCB_LISTS;\n  struct tcp_pcb *cpcb;\n\n  LWIP_ERROR(\"tcp_bind: can only bind in state CLOSED\", pcb->state == CLOSED, return ERR_ISCONN);\n\n#if SO_REUSE\n  /* Unless the REUSEADDR flag is set,\n     we have to check the pcbs in TIME-WAIT state, also.\n     We do not dump TIME_WAIT pcb's; they can still be matched by incoming\n     packets using both local and remote IP addresses and ports to distinguish.\n   */\n  if ((pcb->so_options & SOF_REUSEADDR) != 0) {\n    max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;\n  }\n#endif /* SO_REUSE */\n\n  if (port == 0) {\n    port = tcp_new_port();\n  }\n\n  /* Check if the address already is in use (on all lists) */\n  for (i = 0; i < max_pcb_list; i++) {\n    for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {\n      if (cpcb->local_port == port) {\n#if SO_REUSE\n        /* Omit checking for the same port if both pcbs have REUSEADDR set.\n           For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in\n           tcp_connect. */\n        if (((pcb->so_options & SOF_REUSEADDR) == 0) ||\n          ((cpcb->so_options & SOF_REUSEADDR) == 0))\n#endif /* SO_REUSE */\n        {\n          if (ip_addr_isany(&(cpcb->local_ip)) ||\n              ip_addr_isany(ipaddr) ||\n              ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\n              //os_printf(\"Address in use\\n\");\n            return ERR_USE;\n          }\n        }\n      }\n    }\n  }\n\n  if (!ip_addr_isany(ipaddr)) {\n    pcb->local_ip = *ipaddr;\n  }\n  pcb->local_port = port;\n  TCP_REG(&tcp_bound_pcbs, pcb);\n  LWIP_DEBUGF(TCP_DEBUG, (\"tcp_bind: bind to port %\"U16_F\"\\n\", port));\n  return ERR_OK;\n}\n#if LWIP_CALLBACK_API\n/**\n * Default accept callback if no accept callback is specified by the user.\n */\nstatic err_t\ntcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_UNUSED_ARG(pcb);\n  LWIP_UNUSED_ARG(err);\n\n  return ERR_ABRT;\n}\n#endif /* LWIP_CALLBACK_API */\n\n/**\n * Set the state of the connection to be LISTEN, which means that it\n * is able to accept incoming connections. The protocol control block\n * is reallocated in order to consume less memory. Setting the\n * connection to LISTEN is an irreversible process.\n *��ĳ���󶨵Ŀ��ƿ���Ϊ����״̬\n * @param pcb the original tcp_pcb �����Ŀ��ƿ����\n * @param backlog the incoming connections queue limit\n * @return tcp_pcb used for listening, consumes less memory.ָ������״̬�Ŀ��ƿ�\n *\n * @note The original tcp_pcb is freed. This function therefore has to be\n *       called like this:\n *             tpcb = tcp_listen(tpcb);\n */\nstruct tcp_pcb *\ntcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)\n{\n  struct tcp_pcb_listen *lpcb;\n\n  LWIP_UNUSED_ARG(backlog);\n  LWIP_ERROR(\"tcp_listen: pcb already connected\", pcb->state == CLOSED, return NULL);\n\n  /* already listening? */\n  if (pcb->state == LISTEN) {\n    return pcb;\n  }\n#if SO_REUSE\n  if ((pcb->so_options & SOF_REUSEADDR) != 0) {\n    /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage\n       is declared (listen-/connection-pcb), we have to make sure now that\n       this port is only used once for every local IP. */\n    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {\n      if (lpcb->local_port == pcb->local_port) {\n        if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {\n          /* this address/port is already used */\n          return NULL;\n        }\n      }\n    }\n  }\n#endif /* SO_REUSE */\n  lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);//�����ڴ�ؿռ�\n  if (lpcb == NULL) {\n    return NULL;\n  }\n  lpcb->callback_arg = pcb->callback_arg;\n  lpcb->local_port = pcb->local_port;\n  lpcb->state = LISTEN;\n  lpcb->prio = pcb->prio;\n  lpcb->so_options = pcb->so_options;\n  lpcb->so_options |= SOF_ACCEPTCONN;\n  lpcb->ttl = pcb->ttl;\n  lpcb->tos = pcb->tos;\n  ip_addr_copy(lpcb->local_ip, pcb->local_ip);\n  if (pcb->local_port != 0) {\n    TCP_RMV(&tcp_bound_pcbs, pcb);\n  }\n  memp_free(MEMP_TCP_PCB, pcb);\n#if LWIP_CALLBACK_API\n  lpcb->accept = tcp_accept_null;//���ܿͻ������ӵ�Ĭ�ϻص�����\n#endif /* LWIP_CALLBACK_API */\n#if TCP_LISTEN_BACKLOG\n  lpcb->accepts_pending = 0;\n  lpcb->backlog = (backlog ? backlog : 1);\n#endif /* TCP_LISTEN_BACKLOG */\n  TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);//���ƿ����tcp_listen_pcbs�����ײ�\n  return (struct tcp_pcb *)lpcb;\n}\n\n/** \n * Update the state that tracks the available window space to advertise.\n *\n * Returns how much extra window would be advertised if we sent an\n * update now.\n */\nu32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)\n{\n  u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;\n\n  if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) {\n    /* we can advertise more window */\n    pcb->rcv_ann_wnd = pcb->rcv_wnd;\n    return new_right_edge - pcb->rcv_ann_right_edge;\n  } else {\n    if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {\n      /* Can happen due to other end sending out of advertised window,\n       * but within actual available (but not yet advertised) window */\n      pcb->rcv_ann_wnd = 0;\n    } else {\n      /* keep the right edge of window constant */\n      u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;\n      LWIP_ASSERT(\"new_rcv_ann_wnd <= 0xffff\", new_rcv_ann_wnd <= 0xffff);\n      pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd;\n    }\n    return 0;\n  }\n}\n\n/**\n * This function should be called by the application when it has\n * processed the data. The purpose is to advertise a larger window\n * when the data has been processed.\n *Ӧ�ó�����ݴ�����Ϻ�֪ͨ�ں˸��½��մ���\n * @param pcb the tcp_pcb for which data is read\n * @param len the amount of bytes that have been read by the application\n */\nvoid\ntcp_recved(struct tcp_pcb *pcb, u16_t len)\n{\n  int wnd_inflation;\n\n  LWIP_ASSERT(\"tcp_recved: len would wrap rcv_wnd\\n\",\n              len <= 0xffff - pcb->rcv_wnd );\n\n  pcb->rcv_wnd += len;\n  if (pcb->rcv_wnd > TCP_WND) {\n    pcb->rcv_wnd = TCP_WND;\n  }\n\n  wnd_inflation = tcp_update_rcv_ann_wnd(pcb);\n\n  /* If the change in the right edge of window is significant (default\n   * watermark is TCP_WND/4), then send an explicit update now.\n   * Otherwise wait for a packet to be sent in the normal course of\n   * events (or more window to be available later) */\n  if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) {\n    tcp_ack_now(pcb);\n    tcp_output(pcb);\n  }\n\n  LWIP_DEBUGF(TCP_DEBUG, (\"tcp_recved: recveived %\"U16_F\" bytes, wnd %\"U16_F\" (%\"U16_F\").\\n\",\n         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));\n}\n\n/**\n * A nastly hack featuring 'goto' statements that allocates a\n * new TCP local port.\n *\n * @return a new (free) local TCP port number\n */\nstatic u16_t\ntcp_new_port(void)\n{\n  int i;\n  struct tcp_pcb *pcb;\n#ifndef TCP_LOCAL_PORT_RANGE_START\n#define TCP_LOCAL_PORT_RANGE_START 4096\n#define TCP_LOCAL_PORT_RANGE_END   0x7fff\n#endif\n  static u16_t port = TCP_LOCAL_PORT_RANGE_START;\n  \n again:\n  if (++port >= TCP_LOCAL_PORT_RANGE_END) {\n    port = TCP_LOCAL_PORT_RANGE_START;\n  }\n  /* Check all PCB lists. */\n  for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {  \n    for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {\n      if (pcb->local_port == port) {\n        goto again;\n      }\n    }\n  }\n  return port;\n}\n\n/**\n * Connects to another host. The function given as the \"connected\"\n * argument will be called when the connection has been established.\n *�����������һ��SYN���ֱ���\n * @param pcb the tcp_pcb used to establish the connection �����Ŀ��ƿ����\n * @param ipaddr the remote ip address to connect to ������IP��ַ\n * @param port the remote tcp port to connect to �������˿ں�\n * @param connected callback function to call when connected (or on error)\n * @return ERR_VAL if invalid arguments are given\n *         ERR_OK if connect request has been sent\n *         other err_t values if connect request couldn't be sent\n */\nerr_t\ntcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,\n      tcp_connected_fn connected)\n{\n  err_t ret;\n  u32_t iss;\n  u16_t old_local_port;\n\n  LWIP_ERROR(\"tcp_connect: can only connected from state CLOSED\", pcb->state == CLOSED, return ERR_ISCONN);\n\n  LWIP_DEBUGF(TCP_DEBUG, (\"tcp_connect to port %\"U16_F\"\\n\", port));\n  if (ipaddr != NULL) {\n    pcb->remote_ip = *ipaddr;//������IP��ַ��Ч�������Ӽ�¼�м�¼��IP��ַ�����򷵻ش���\n  } else {\n    return ERR_VAL;\n  }\n  pcb->remote_port = port;//��¼�������˿�(Ŀ�Ķ˿�)\n\n  /* check if we have a route to the remote host */\n  if (ip_addr_isany(&(pcb->local_ip))) {\n    /* no local IP address set, yet. */\n    struct netif *netif = ip_route(&(pcb->remote_ip));\n    if (netif == NULL) {\n      /* Don't even try to send a SYN packet if we have no route\n         since that will fail. */\n      return ERR_RTE;\n    }\n    /* Use the netif's IP address as local address. */\n    ip_addr_copy(pcb->local_ip, netif->ip_addr);\n  }\n\n  old_local_port = pcb->local_port;\n  if (pcb->local_port == 0) {\n    pcb->local_port = tcp_new_port();\n\n  }\n#if SO_REUSE\n  if ((pcb->so_options & SOF_REUSEADDR) != 0) {\n    /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure\n       now that the 5-tuple is unique. */\n    struct tcp_pcb *cpcb;\n    int i;\n    /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */\n    for (i = 2; i < NUM_TCP_PCB_LISTS; i++) {\n      for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {\n        if ((cpcb->local_port == pcb->local_port) &&\n            (cpcb->remote_port == port) &&\n            ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) &&\n            ip_addr_cmp(&cpcb->remote_ip, ipaddr)) {\n          /* linux returns EISCONN here, but ERR_USE should be OK for us */\n          return ERR_USE;\n        }\n      }\n    }\n  }\n#endif /* SO_REUSE */\n  iss = tcp_next_iss();//��ʼ�����\n  pcb->rcv_nxt = 0;//���÷��ʹ��ڵĸ����ֶ�\n  pcb->snd_nxt = iss;\n  pcb->lastack = iss - 1;\n  pcb->snd_lbb = iss - 1;\n  pcb->rcv_wnd = TCP_WND;//����Ĭ�Ͻ��մ��ڸ����ֶ�ֵ\n  pcb->rcv_ann_wnd = TCP_WND;\n  pcb->rcv_ann_right_edge = pcb->rcv_nxt;\n  pcb->snd_wnd = TCP_WND;\n  /* As initial send MSS, we use TCP_MSS but limit it to 536.\n     The send MSS is updated when an MSS option is received. */\n  pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;//��ʼ������Ķδ�С\n#if TCP_CALCULATE_EFF_SEND_MSS\n  pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);\n#endif /* TCP_CALCULATE_EFF_SEND_MSS */\n  pcb->cwnd = 1;//��ʼ�������\n  pcb->ssthresh = pcb->mss * 10;\n#if LWIP_CALLBACK_API\n  pcb->connected = connected;//ע��connected�ص�����\n#else /* LWIP_CALLBACK_API */  \n  LWIP_UNUSED_ARG(connected);\n#endif /* LWIP_CALLBACK_API */\n\n  /* Send a SYN together with the MSS option. */\n  ret = tcp_enqueue_flags(pcb, TCP_SYN);\n  if (ret == ERR_OK) {\n    /* SYN segment was enqueued, changed the pcbs state now ���ƿ�����ΪSYN_SENT ״̬*/\n    pcb->state = SYN_SENT;\n    if (old_local_port != 0) {\n      TCP_RMV(&tcp_bound_pcbs, pcb);\n    }\n    TCP_REG(&tcp_active_pcbs, pcb);\n    snmp_inc_tcpactiveopens();\n\n    tcp_output(pcb);//�����ƿ������ӵı��ķ��ͳ�ȥ\n  }\n  return ret;\n}\n\n/**\n * Called every 500 ms and implements the retransmission timer and the timer that\n * removes PCBs that have been in TIME-WAIT for enough time. It also increments\n * various timers such as the inactivity timer in each PCB.\n *\n * Automatically called from tcp_tmr().\n */\nvoid\ntcp_slowtmr(void)\n{\n  struct tcp_pcb *pcb, *prev;\n  u16_t eff_wnd;\n  u8_t pcb_remove;      /* flag if a PCB should be removed */\n  u8_t pcb_reset;       /* flag if a RST should be sent when removing */\n  err_t err;\n\n  err = ERR_OK;\n\n  ++tcp_ticks;\n\n  /* Steps through all of the active PCBs. */\n  prev = NULL;\n  pcb = tcp_active_pcbs;\n  if (pcb == NULL) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: no active pcbs\\n\"));\n  }\n  while (pcb != NULL) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: processing active pcb\\n\"));\n    LWIP_ASSERT(\"tcp_slowtmr: active pcb->state != CLOSED\\n\", pcb->state != CLOSED);\n    LWIP_ASSERT(\"tcp_slowtmr: active pcb->state != LISTEN\\n\", pcb->state != LISTEN);\n    LWIP_ASSERT(\"tcp_slowtmr: active pcb->state != TIME-WAIT\\n\", pcb->state != TIME_WAIT);\n\n    pcb_remove = 0;\n    pcb_reset = 0;\n\n    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {\n      ++pcb_remove;\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: max SYN retries reached\\n\"));\n    }\n    else if (pcb->nrtx == TCP_MAXRTX) {\n      ++pcb_remove;\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: max DATA retries reached\\n\"));\n    } else {\n      if (pcb->persist_backoff > 0) {\n        /* If snd_wnd is zero, use persist timer to send 1 byte probes\n         * instead of using the standard retransmission mechanism. */\n        pcb->persist_cnt++;\n        if (pcb->persist_cnt >= system_get_data_of_array_8(tcp_persist_backoff, pcb->persist_backoff-1)) {\n          pcb->persist_cnt = 0;\n          if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {\n            pcb->persist_backoff++;\n          }\n          tcp_zero_window_probe(pcb);\n        }\n      } else {\n        /* Increase the retransmission timer if it is running */\n        if(pcb->rtime >= 0)\n          ++pcb->rtime;\n\n        if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {\n          /* Time for a retransmission. */\n          LWIP_DEBUGF(TCP_RTO_DEBUG, (\"tcp_slowtmr: rtime %\"S16_F\n                                      \" pcb->rto %\"S16_F\"\\n\",\n                                      pcb->rtime, pcb->rto));\n\n          /* Double retransmission time-out unless we are trying to\n           * connect to somebody (i.e., we are in SYN_SENT). */\n          if (pcb->state != SYN_SENT) {\n            pcb->rto = ((pcb->sa >> 3) + pcb->sv) << system_get_data_of_array_8(tcp_backoff, pcb->nrtx);\n//\t\t\tif (pcb->rto >= TCP_MAXRTO)\n//            \tpcb->rto >>= 1;\n          }\n\n          /* Reset the retransmission timer. */\n          pcb->rtime = 0;\n\n          /* Reduce congestion window and ssthresh. */\n          eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);\n          pcb->ssthresh = eff_wnd >> 1;\n          if (pcb->ssthresh < (pcb->mss << 1)) {\n            pcb->ssthresh = (pcb->mss << 1);\n          }\n          pcb->cwnd = pcb->mss;\n          LWIP_DEBUGF(TCP_CWND_DEBUG, (\"tcp_slowtmr: cwnd %\"U16_F\n                                       \" ssthresh %\"U16_F\"\\n\",\n                                       pcb->cwnd, pcb->ssthresh));\n \n          /* The following needs to be called AFTER cwnd is set to one\n             mss - STJ */\n          tcp_rexmit_rto(pcb);\n        }\n      }\n    }\n    /* Check if this PCB has stayed too long in FIN-WAIT-2 */\n    if (pcb->state == FIN_WAIT_2) {\n      if ((u32_t)(tcp_ticks - pcb->tmr) >\n          TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {\n        ++pcb_remove;\n        LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\\n\"));\n      }\n    }\n\n    /* Check if KEEPALIVE should be sent */\n    if((pcb->so_options & SOF_KEEPALIVE) &&\n       ((pcb->state == ESTABLISHED) ||\n        (pcb->state == CLOSE_WAIT))) {\n#if LWIP_TCP_KEEPALIVE\n      if((u32_t)(tcp_ticks - pcb->tmr) >\n         (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))\n         / TCP_SLOW_INTERVAL)\n#else      \n      if((u32_t)(tcp_ticks - pcb->tmr) >\n         (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)\n#endif /* LWIP_TCP_KEEPALIVE */\n      {\n        LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\".\\n\",\n                                ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),\n                                ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));\n        \n        ++pcb_remove;\n        ++pcb_reset;\n      }\n#if LWIP_TCP_KEEPALIVE\n      else if((u32_t)(tcp_ticks - pcb->tmr) > \n              (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)\n              / TCP_SLOW_INTERVAL)\n#else\n      else if((u32_t)(tcp_ticks - pcb->tmr) > \n              (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT) \n              / TCP_SLOW_INTERVAL)\n#endif /* LWIP_TCP_KEEPALIVE */\n      {\n        tcp_keepalive(pcb);\n        pcb->keep_cnt_sent++;\n      }\n    }\n\n    /* If this PCB has queued out of sequence data, but has been\n       inactive for too long, will drop the data (it will eventually\n       be retransmitted). */\n#if TCP_QUEUE_OOSEQ\n    if (pcb->ooseq != NULL &&\n        (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {\n      tcp_segs_free(pcb->ooseq);\n      pcb->ooseq = NULL;\n      LWIP_DEBUGF(TCP_CWND_DEBUG, (\"tcp_slowtmr: dropping OOSEQ queued data\\n\"));\n    }\n#endif /* TCP_QUEUE_OOSEQ */\n\n    /* Check if this PCB has stayed too long in SYN-RCVD */\n    if (pcb->state == SYN_RCVD) {\n      if ((u32_t)(tcp_ticks - pcb->tmr) >\n          TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {\n        ++pcb_remove;\n        LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: removing pcb stuck in SYN-RCVD\\n\"));\n      }\n    }\n\n    /* Check if this PCB has stayed too long in LAST-ACK */\n    if (pcb->state == LAST_ACK) {\n      if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {\n        ++pcb_remove;\n        LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: removing pcb stuck in LAST-ACK\\n\"));\n      }\n    }\n\n    /* If the PCB should be removed, do it. */\n    if (pcb_remove) {\n      struct tcp_pcb *pcb2;\n      tcp_pcb_purge(pcb);\n      /* Remove PCB from tcp_active_pcbs list. */\n      if (prev != NULL) {\n        LWIP_ASSERT(\"tcp_slowtmr: middle tcp != tcp_active_pcbs\", pcb != tcp_active_pcbs);\n        prev->next = pcb->next;\n      } else {\n        /* This PCB was the first. */\n        LWIP_ASSERT(\"tcp_slowtmr: first pcb == tcp_active_pcbs\", tcp_active_pcbs == pcb);\n        tcp_active_pcbs = pcb->next;\n      }\n      \n      if (pcb_reset) {\n        tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,\n          pcb->local_port, pcb->remote_port);\n      }\n\t  \n\t  TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);\n      pcb2 = pcb;\n      pcb = pcb->next;\n      memp_free(MEMP_TCP_PCB, pcb2);\n    } else {\n      /* get the 'next' element now and work with 'prev' below (in case of abort) */\n      prev = pcb;\n      pcb = pcb->next;\n\n      /* We check if we should poll the connection. */\n      ++prev->polltmr;\n      if (prev->polltmr >= prev->pollinterval) {\n        prev->polltmr = 0;\n        LWIP_DEBUGF(TCP_DEBUG, (\"tcp_slowtmr: polling application\\n\"));\n        TCP_EVENT_POLL(prev, err);\n        /* if err == ERR_ABRT, 'prev' is already deallocated */\n        if (err == ERR_OK) {\n          tcp_output(prev);\n        }\n      }\n    }\n  }\n\n  \n  /* Steps through all of the TIME-WAIT PCBs. */\n  prev = NULL;\n  pcb = tcp_tw_pcbs;\n  while (pcb != NULL) {\n    LWIP_ASSERT(\"tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT\", pcb->state == TIME_WAIT);\n    pcb_remove = 0;\n\n    /* Check if this PCB has stayed long enough in TIME-WAIT */\n    if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {\n      ++pcb_remove;\n    }\n    \n\n\n    /* If the PCB should be removed, do it. */\n    if (pcb_remove) {\n      struct tcp_pcb *pcb2;\n      tcp_pcb_purge(pcb);\n      /* Remove PCB from tcp_tw_pcbs list. */\n      if (prev != NULL) {\n        LWIP_ASSERT(\"tcp_slowtmr: middle tcp != tcp_tw_pcbs\", pcb != tcp_tw_pcbs);\n        prev->next = pcb->next;\n      } else {\n        /* This PCB was the first. */\n        LWIP_ASSERT(\"tcp_slowtmr: first pcb == tcp_tw_pcbs\", tcp_tw_pcbs == pcb);\n        tcp_tw_pcbs = pcb->next;\n      }\n      pcb2 = pcb;\n      pcb = pcb->next;\n      memp_free(MEMP_TCP_PCB, pcb2);\n    } else {\n      prev = pcb;\n      pcb = pcb->next;\n    }\n  }\n}\n\n/**\n * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously\n * \"refused\" by upper layer (application) and sends delayed ACKs.\n *\n * Automatically called from tcp_tmr().\n */\nvoid\ntcp_fasttmr(void)\n{\n  struct tcp_pcb *pcb = tcp_active_pcbs;\n\n  while(pcb != NULL) {\n    struct tcp_pcb *next = pcb->next;\n    /* If there is data which was previously \"refused\" by upper layer */\n    if (pcb->refused_data != NULL) {\n      /* Notify again application with data previously received. */\n      err_t err;\n      LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_fasttmr: notify kept packet\\n\"));\n      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);\n      if (err == ERR_OK) {\n        pcb->refused_data = NULL;\n      } else if (err == ERR_ABRT) {\n        /* if err == ERR_ABRT, 'pcb' is already deallocated */\n        pcb = NULL;\n      }\n    }\n\n    /* send delayed ACKs */\n    if (pcb && (pcb->flags & TF_ACK_DELAY)) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_fasttmr: delayed ACK\\n\"));\n      tcp_ack_now(pcb);\n      tcp_output(pcb);\n      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\n    }\n\n    pcb = next;\n  }\n}\n\n/**\n * Deallocates a list of TCP segments (tcp_seg structures).\n *\n * @param seg tcp_seg list of TCP segments to free\n */\nvoid\ntcp_segs_free(struct tcp_seg *seg)\n{\n  while (seg != NULL) {\n    struct tcp_seg *next = seg->next;\n    tcp_seg_free(seg);\n    seg = next;\n  }\n}\n\n/**\n * Frees a TCP segment (tcp_seg structure).\n *\n * @param seg single tcp_seg to free\n */\nvoid\ntcp_seg_free(struct tcp_seg *seg)\n{\n  if (seg != NULL) {\n    if (seg->p != NULL) {\n      pbuf_free(seg->p);\n#if TCP_DEBUG\n      seg->p = NULL;\n#endif /* TCP_DEBUG */\n    }\n    memp_free(MEMP_TCP_SEG, seg);\n  }\n}\n\n/**\n * Sets the priority of a connection.\n *\n * @param pcb the tcp_pcb to manipulate\n * @param prio new priority\n */\nvoid\ntcp_setprio(struct tcp_pcb *pcb, u8_t prio)\n{\n  pcb->prio = prio;\n}\n\n#if TCP_QUEUE_OOSEQ\n/**\n * Returns a copy of the given TCP segment.\n * The pbuf and data are not copied, only the pointers\n *\n * @param seg the old tcp_seg\n * @return a copy of seg\n */ \nstruct tcp_seg *\ntcp_seg_copy(struct tcp_seg *seg)\n{\n  struct tcp_seg *cseg;\n\n  cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG);\n  if (cseg == NULL) {\n    return NULL;\n  }\n  SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); \n  pbuf_ref(cseg->p);\n  return cseg;\n}\n#endif /* TCP_QUEUE_OOSEQ */\n\n#if LWIP_CALLBACK_API\n/**\n * Default receive callback that is called if the user didn't register\n * a recv callback for the pcb.\n */\nerr_t\ntcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\n{\n  LWIP_UNUSED_ARG(arg);\n  if (p != NULL) {\n    tcp_recved(pcb, p->tot_len);\n    pbuf_free(p);\n  } else if (err == ERR_OK) {\n    return tcp_close(pcb);\n  }\n  return ERR_OK;\n}\n#endif /* LWIP_CALLBACK_API */\n\n/**\n * Kills the oldest active connection that has lower priority than prio.\n *\n * @param prio minimum priority\n */\nstatic void ICACHE_FLASH_ATTR\ntcp_kill_prio(u8_t prio)\n{\n  struct tcp_pcb *pcb, *inactive;\n  u32_t inactivity;\n  u8_t mprio;\n\n\n  mprio = TCP_PRIO_MAX;\n  \n  /* We kill the oldest active connection that has lower priority than prio. */\n  inactivity = 0;\n  inactive = NULL;\n  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\n    if (pcb->prio <= prio &&\n       pcb->prio <= mprio &&\n       (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {\n      inactivity = tcp_ticks - pcb->tmr;\n      inactive = pcb;\n      mprio = pcb->prio;\n    }\n  }\n  if (inactive != NULL) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"tcp_kill_prio: killing oldest PCB %p (%\"S32_F\")\\n\",\n           (void *)inactive, inactivity));\n    tcp_abort(inactive);\n  }\n}\n\n/**\n * Kills the oldest connection that is in TIME_WAIT state.\n * Called from tcp_alloc() if no more connections are available.\n */\nstatic void ICACHE_FLASH_ATTR\ntcp_kill_timewait(void)\n{\n  struct tcp_pcb *pcb, *inactive;\n  u32_t inactivity;\n\n  inactivity = 0;\n  inactive = NULL;\n  /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */\n  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\n    if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {\n      inactivity = tcp_ticks - pcb->tmr;\n      inactive = pcb;\n    }\n  }\n  if (inactive != NULL) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%\"S32_F\")\\n\",\n           (void *)inactive, inactivity));\n    tcp_abort(inactive);\n  }\n}\n\n/**\n * Allocate a new tcp_pcb structure.\n *����һ��TCP���ƿ�ṹ������ʼ������ֶ�\n * @param prio priority for the new pcb\t \t\t\t\t�¿��ƿ�����ȼ�\n * @return a new tcp_pcb that initially is in state CLOSED\tָ���¿��ƿ��ָ��\n */\nstruct tcp_pcb *\ntcp_alloc(u8_t prio)\n{\n  struct tcp_pcb *pcb;\n  u32_t iss;\n  \n  pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);//�����ڴ�ؿռ�\n  if (pcb == NULL) {\n\t//os_printf(\"tcp_pcb memory is fail\\n\");\n\t/* Try killing oldest connection in TIME-WAIT. */\n    LWIP_DEBUGF(TCP_DEBUG, (\"tcp_alloc: killing off oldest TIME-WAIT connection\\n\"));\n    tcp_kill_timewait();\n    /* Try to allocate a tcp_pcb again. */\n    pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);\n    if (pcb == NULL) {\n      /* Try killing active connections with lower priority than the new one. */\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_alloc: killing connection with prio lower than %d\\n\", prio));\n      tcp_kill_prio(prio);\n      /* Try to allocate a tcp_pcb again. */\n      pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB);\n      if (pcb != NULL) {\n        /* adjust err stats: memp_malloc failed twice before */\n        MEMP_STATS_DEC(err, MEMP_TCP_PCB);\n      }\n    }\n    if (pcb != NULL) {\n      /* adjust err stats: timewait PCB was freed above */\n      MEMP_STATS_DEC(err, MEMP_TCP_PCB);\n    }\n  }\n  if (pcb != NULL) {\n    os_memset(pcb, 0, sizeof(struct tcp_pcb));\t\t\t\t\t\t//��0\n    pcb->prio = prio;\t\t\t\t\t\t\t\t\t\t\t//�������ȼ�\n    pcb->snd_buf = TCP_SND_BUF;\t\t\t\t\t\t\t//��ʹ�õķ��ͻ������С\n    pcb->snd_queuelen = 0;\t\t\t\t\t\t\t\t\t//��������ռ�õ�pbuf����\n    pcb->rcv_wnd = TCP_WND;\t\t\t\t\t\t\t\t//���մ���\n    pcb->rcv_ann_wnd = TCP_WND;\t\t\t\t\t\t\t//ͨ����մ���\n    pcb->tos = 0;\t\t\t\t\t\t\t\t\t\t\t//��������\n    pcb->ttl = TCP_TTL;\t\t\t\t\t\t\t\t\t\t//ttl�ֶ�\n    /* As initial send MSS, we use TCP_MSS but limit it to 536.\n       The send MSS is updated when an MSS option is received. */\n    pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;\t\t\t\t//��ʼ������Ķ�\n    pcb->rto = 1000 / TCP_SLOW_INTERVAL;\t\t\t\t\t//��ʼ����ʱʱ��\n    pcb->sa = 0;\t\t\t\t\t\t\t\t\t\t\t//��ʼ����RTT��صĲ���\n    pcb->sv = 1000 / TCP_SLOW_INTERVAL;\n    pcb->rtime = -1;\n    pcb->cwnd = 1;\t\t\t\t\t\t\t\t\t\t\t//��ʼ�������\n    iss = tcp_next_iss();\t\t\t\t\t\t\t\t\t\t//��ó�ʼ���к�\n    pcb->snd_wl2 = iss;\t\t\t\t\t\t\t\t\t\t//��ʼ�����ʹ��ڸ����ֶ�\n    pcb->snd_nxt = iss;\n    pcb->lastack = iss;\n    pcb->snd_lbb = iss;   \n    pcb->tmr = tcp_ticks;\t\t\t\t\t\t\t\t\t\t//��¼���ƿ鴴��ϵͳʱ��\n\n    pcb->polltmr = 0;\t\t\t\t\t\t\t\t\t\t//����������¼���ʱ��\n\n#if LWIP_CALLBACK_API\n    pcb->recv = tcp_recv_null;\t\t\t\t\t\t\t\t//ע�������ݵ�Ĭ���ϲ㺯��\n#endif /* LWIP_CALLBACK_API */  \n    \n    /* Init KEEPALIVE timer */\n    pcb->keep_idle  = TCP_KEEPIDLE_DEFAULT;\n    \n#if LWIP_TCP_KEEPALIVE\n    pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;\n    pcb->keep_cnt   = TCP_KEEPCNT_DEFAULT;\n#endif /* LWIP_TCP_KEEPALIVE */\n\n    pcb->keep_cnt_sent = 0;\t\t\t\t\t\t\t\t\t//���ķ��ʹ���\n  }\n  return pcb;\n}\n\n/**\n * Creates a new TCP protocol control block but doesn't place it on\n * any of the TCP PCB lists.\n * The pcb is not put on any list until binding using tcp_bind().\n *\n * @internal: Maybe there should be a idle TCP PCB list where these\n * PCBs are put on. Port reservation using tcp_bind() is implemented but\n * allocated pcbs that are not bound can't be killed automatically if wanting\n * to allocate a pcb with higher prio (@see tcp_kill_prio())\n *\n * @return a new tcp_pcb that initially is in state CLOSED\n */\nstruct tcp_pcb *\ntcp_new(void)\n{\n  return tcp_alloc(TCP_PRIO_NORMAL);\n}\n\n/**\n * Used to specify the argument that should be passed callback\n * functions.\n *����ƿ��callback_arg�ֶ�ע���û���ݣ���tcp_recv�Ⱥ���ص�ʱ��\n* ���ֶν���Ϊ����ݸ��������\n * @param pcb tcp_pcb to set the callback argument\n * @param arg void pointer argument to pass to callback functions\n */ \nvoid\ntcp_arg(struct tcp_pcb *pcb, void *arg)\n{  \n  pcb->callback_arg = arg;\n}\n#if LWIP_CALLBACK_API\n\n/**\n * Used to specify the function that should be called when a TCP\n * connection receives data.\n *����ƿ��recv�ֶ�ע�ắ���յ����ʱ�ص�\n * @param pcb tcp_pcb to set the recv callback\n * @param recv callback function to call for this pcb when data is received\n */ \nvoid\ntcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)\n{\n  pcb->recv = recv;\n}\n\n/**\n * Used to specify the function that should be called when TCP data\n * has been successfully delivered to the remote host.\n *����ƿ�send �ֶ�ע�ắ����ݷ��ͳɹ���ص�\n * @param pcb tcp_pcb to set the sent callback\n * @param sent callback function to call for this pcb when data is successfully sent\n */ \nvoid\ntcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)\n{\n  pcb->sent = sent;\n}\n\n/**\n * Used to specify the function that should be called when a fatal error\n * has occured on the connection.\n *����ƿ�err �ֶ�ע�ắ�����������ص�\n * @param pcb tcp_pcb to set the err callback\n * @param err callback function to call for this pcb when a fatal error\n *        has occured on the connection\n */ \nvoid\ntcp_err(struct tcp_pcb *pcb, tcp_err_fn err)\n{\n  pcb->errf = err;\n}\n\n/**\n * Used for specifying the function that should be called when a\n * LISTENing connection has been connected to another host.\n *����ƿ��accept�ֶ�ע�ắ����������ʱ�ص�\n * @param pcb tcp_pcb to set the accept callback\n * @param accept callback function to call for this pcb when LISTENing\n *        connection has been connected to another host\n */ \nvoid\ntcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)\n{\n  pcb->accept = accept;\n}\n#endif /* LWIP_CALLBACK_API */\n\n\n/**\n * Used to specify the function that should be called periodically\n * from TCP. The interval is specified in terms of the TCP coarse\n * timer interval, which is called twice a second.\n *����ƿ��POLL�ֶ�ע�ắ��ú��������Ա�����\n */ \nvoid\ntcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval)\n{\n#if LWIP_CALLBACK_API\n  pcb->poll = poll;\n#else /* LWIP_CALLBACK_API */  \n  LWIP_UNUSED_ARG(poll);\n#endif /* LWIP_CALLBACK_API */  \n  pcb->pollinterval = interval;\n}\n\n/**\n * Purges a TCP PCB. Removes any buffered data and frees the buffer memory\n * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).\n *\n * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!\n */\nvoid\ntcp_pcb_purge(struct tcp_pcb *pcb)\n{\n  if (pcb->state != CLOSED &&\n     pcb->state != TIME_WAIT &&\n     pcb->state != LISTEN) {\n\n    LWIP_DEBUGF(TCP_DEBUG, (\"tcp_pcb_purge\\n\"));\n\n#if TCP_LISTEN_BACKLOG\n    if (pcb->state == SYN_RCVD) {\n      /* Need to find the corresponding listen_pcb and decrease its accepts_pending */\n      struct tcp_pcb_listen *lpcb;\n      LWIP_ASSERT(\"tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL\",\n        tcp_listen_pcbs.listen_pcbs != NULL);\n      for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {\n        if ((lpcb->local_port == pcb->local_port) &&\n            (ip_addr_isany(&lpcb->local_ip) ||\n             ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {\n            /* port and address of the listen pcb match the timed-out pcb */\n            LWIP_ASSERT(\"tcp_pcb_purge: listen pcb does not have accepts pending\",\n              lpcb->accepts_pending > 0);\n            lpcb->accepts_pending--;\n            break;\n          }\n      }\n    }\n#endif /* TCP_LISTEN_BACKLOG */\n\n\n    if (pcb->refused_data != NULL) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_pcb_purge: data left on ->refused_data\\n\"));\n      pbuf_free(pcb->refused_data);\n      pcb->refused_data = NULL;\n    }\n    if (pcb->unsent != NULL) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_pcb_purge: not all data sent\\n\"));\n    }\n    if (pcb->unacked != NULL) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_pcb_purge: data left on ->unacked\\n\"));\n    }\n#if TCP_QUEUE_OOSEQ\n    if (pcb->ooseq != NULL) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_pcb_purge: data left on ->ooseq\\n\"));\n    }\n    tcp_segs_free(pcb->ooseq);\n    pcb->ooseq = NULL;\n#endif /* TCP_QUEUE_OOSEQ */\n\n    /* Stop the retransmission timer as it will expect data on unacked\n       queue if it fires */\n    pcb->rtime = -1;\n\n    tcp_segs_free(pcb->unsent);\n    tcp_segs_free(pcb->unacked);\n    pcb->unacked = pcb->unsent = NULL;\n#if TCP_OVERSIZE\n    pcb->unsent_oversize = 0;\n#endif /* TCP_OVERSIZE */\n  }\n}\n\n/**\n * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.\n *\n * @param pcblist PCB list to purge.\n * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated!\n */\nvoid\ntcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)\n{\n  TCP_RMV(pcblist, pcb);\n\n  tcp_pcb_purge(pcb);\n  \n  /* if there is an outstanding delayed ACKs, send it */\n  if (pcb->state != TIME_WAIT &&\n     pcb->state != LISTEN &&\n     pcb->flags & TF_ACK_DELAY) {\n    pcb->flags |= TF_ACK_NOW;\n    tcp_output(pcb);\n  }\n\n  if (pcb->state != LISTEN) {\n    LWIP_ASSERT(\"unsent segments leaking\", pcb->unsent == NULL);\n    LWIP_ASSERT(\"unacked segments leaking\", pcb->unacked == NULL);\n#if TCP_QUEUE_OOSEQ\n    LWIP_ASSERT(\"ooseq segments leaking\", pcb->ooseq == NULL);\n#endif /* TCP_QUEUE_OOSEQ */\n  }\n\n  pcb->state = CLOSED;\n\n  LWIP_ASSERT(\"tcp_pcb_remove: tcp_pcbs_sane()\", tcp_pcbs_sane());\n}\n\n/**\n * Calculates a new initial sequence number for new connections.\n *\n * @return u32_t pseudo random sequence number\n */\nu32_t\ntcp_next_iss(void)\n{\n  static u32_t iss = 6510;\n  \n  again:\n    iss += tcp_ticks;       /* XXX */\n    if (iss == 0)\n  \t   goto again;\n\n  return iss;\n}\n\n#if TCP_CALCULATE_EFF_SEND_MSS\n/**\n * Calcluates the effective send mss that can be used for a specific IP address\n * by using ip_route to determin the netif used to send to the address and\n * calculating the minimum of TCP_MSS and that netif's mtu (if set).\n */\nu16_t\ntcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)\n{\n  u16_t mss_s;\n  struct netif *outif;\n\n  outif = ip_route(addr);\n  if ((outif != NULL) && (outif->mtu != 0)) {\n    mss_s = outif->mtu - IP_HLEN - TCP_HLEN;\n    /* RFC 1122, chap 4.2.2.6:\n     * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize\n     * We correct for TCP options in tcp_write(), and don't support IP options.\n     */\n    sendmss = LWIP_MIN(sendmss, mss_s);\n  }\n  return sendmss;\n}\n#endif /* TCP_CALCULATE_EFF_SEND_MSS */\n\n#if TCP_DEBUG\nconst char*\ntcp_debug_state_str(enum tcp_state s)\n{\n  system_get_string_from_flash(tcp_state_str_rodata[s], tcp_state_str, 12);\n\n  return tcp_state_str;\n}\n#endif\n\n#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG\n/**\n * Print a tcp header for debugging purposes.\n *\n * @param tcphdr pointer to a struct tcp_hdr\n */\nvoid\ntcp_debug_print(struct tcp_hdr *tcphdr)\n{\n  LWIP_DEBUGF(TCP_DEBUG, (\"TCP header:\\n\"));\n  LWIP_DEBUGF(TCP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(TCP_DEBUG, (\"|    %5\"U16_F\"      |    %5\"U16_F\"      | (src port, dest port)\\n\",\n         ntohs(tcphdr->src), ntohs(tcphdr->dest)));\n  LWIP_DEBUGF(TCP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(TCP_DEBUG, (\"|           %010\"U32_F\"          | (seq no)\\n\",\n          ntohl(tcphdr->seqno)));\n  LWIP_DEBUGF(TCP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(TCP_DEBUG, (\"|           %010\"U32_F\"          | (ack no)\\n\",\n         ntohl(tcphdr->ackno)));\n  LWIP_DEBUGF(TCP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(TCP_DEBUG, (\"| %2\"U16_F\" |   |%\"U16_F\"%\"U16_F\"%\"U16_F\"%\"U16_F\"%\"U16_F\"%\"U16_F\"|     %5\"U16_F\"     | (hdrlen, flags (\",\n       TCPH_HDRLEN(tcphdr),\n         TCPH_FLAGS(tcphdr) >> 5 & 1,\n         TCPH_FLAGS(tcphdr) >> 4 & 1,\n         TCPH_FLAGS(tcphdr) >> 3 & 1,\n         TCPH_FLAGS(tcphdr) >> 2 & 1,\n         TCPH_FLAGS(tcphdr) >> 1 & 1,\n         TCPH_FLAGS(tcphdr) & 1,\n         ntohs(tcphdr->wnd)));\n  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));\n  LWIP_DEBUGF(TCP_DEBUG, (\"), win)\\n\"));\n  LWIP_DEBUGF(TCP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(TCP_DEBUG, (\"|    0x%04\"X16_F\"     |     %5\"U16_F\"     | (chksum, urgp)\\n\",\n         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));\n  LWIP_DEBUGF(TCP_DEBUG, (\"+-------------------------------+\\n\"));\n}\n\n/**\n * Print a tcp state for debugging purposes.\n *\n * @param s enum tcp_state to print\n */\nvoid\ntcp_debug_print_state(enum tcp_state s)\n{\n  LWIP_DEBUGF(TCP_DEBUG, (\"State: %s\\n\", tcp_state_str[s]));\n}\n\n/**\n * Print tcp flags for debugging purposes.\n *\n * @param flags tcp flags, all active flags are printed\n */\nvoid\ntcp_debug_print_flags(u8_t flags)\n{\n  if (flags & TCP_FIN) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"FIN \"));\n  }\n  if (flags & TCP_SYN) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"SYN \"));\n  }\n  if (flags & TCP_RST) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"RST \"));\n  }\n  if (flags & TCP_PSH) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"PSH \"));\n  }\n  if (flags & TCP_ACK) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"ACK \"));\n  }\n  if (flags & TCP_URG) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"URG \"));\n  }\n  if (flags & TCP_ECE) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"ECE \"));\n  }\n  if (flags & TCP_CWR) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"CWR \"));\n  }\n  LWIP_DEBUGF(TCP_DEBUG, (\"\\n\"));\n}\n\n/**\n * Print all tcp_pcbs in every list for debugging purposes.\n */\nvoid\ntcp_debug_print_pcbs(void)\n{\n  struct tcp_pcb *pcb;\n  LWIP_DEBUGF(TCP_DEBUG, (\"Active PCB states:\\n\"));\n  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"Local port %\"U16_F\", foreign port %\"U16_F\" snd_nxt %\"U32_F\" rcv_nxt %\"U32_F\" \",\n                       pcb->local_port, pcb->remote_port,\n                       pcb->snd_nxt, pcb->rcv_nxt));\n    tcp_debug_print_state(pcb->state);\n  }    \n  LWIP_DEBUGF(TCP_DEBUG, (\"Listen PCB states:\\n\"));\n  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"Local port %\"U16_F\", foreign port %\"U16_F\" snd_nxt %\"U32_F\" rcv_nxt %\"U32_F\" \",\n                       pcb->local_port, pcb->remote_port,\n                       pcb->snd_nxt, pcb->rcv_nxt));\n    tcp_debug_print_state(pcb->state);\n  }    \n  LWIP_DEBUGF(TCP_DEBUG, (\"TIME-WAIT PCB states:\\n\"));\n  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"Local port %\"U16_F\", foreign port %\"U16_F\" snd_nxt %\"U32_F\" rcv_nxt %\"U32_F\" \",\n                       pcb->local_port, pcb->remote_port,\n                       pcb->snd_nxt, pcb->rcv_nxt));\n    tcp_debug_print_state(pcb->state);\n  }    \n}\n\n/**\n * Check state consistency of the tcp_pcb lists.\n */\ns16_t\ntcp_pcbs_sane(void)\n{\n  struct tcp_pcb *pcb;\n  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\n    LWIP_ASSERT(\"tcp_pcbs_sane: active pcb->state != CLOSED\", pcb->state != CLOSED);\n    LWIP_ASSERT(\"tcp_pcbs_sane: active pcb->state != LISTEN\", pcb->state != LISTEN);\n    LWIP_ASSERT(\"tcp_pcbs_sane: active pcb->state != TIME-WAIT\", pcb->state != TIME_WAIT);\n  }\n  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\n    LWIP_ASSERT(\"tcp_pcbs_sane: tw pcb->state == TIME-WAIT\", pcb->state == TIME_WAIT);\n  }\n  return 1;\n}\n#endif /* TCP_DEBUG */\n\n#endif /* LWIP_TCP */\n"
  },
  {
    "path": "app/lwip/core/tcp_in.c",
    "content": "/**\n * @file\n * Transmission Control Protocol, incoming traffic\n *\n * The input processing functions of the TCP layer.\n *\n * These functions are generally called in the order (ip_input() ->)\n * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).\n * \n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/tcp_impl.h\"\n#include \"lwip/def.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/inet_chksum.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/snmp.h\"\n#include \"arch/perf.h\"\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/* These variables are global to all functions involved in the input\n   processing of TCP segments. They are set by the tcp_input()\n   function. */\nstatic struct tcp_seg inseg;\t\t//tcp_seg�ṹ����������ı��Ķ�\nstatic struct tcp_hdr *tcphdr;\t\t//���Ķ���TCP�ײ�\nstatic struct ip_hdr *iphdr;\t\t//IP��ݰ��ײ�\nstatic u32_t seqno, ackno;\t\t//TCP�ײ�������ֶ���ȷ�Ϻ��ֶ�\nstatic u8_t flags;\t\t\t\t//�ײ���־�ֶ�\nstatic u16_t tcplen;\t\t\t\t//TCP���ĳ���\n\nstatic u8_t recv_flags;\t\t\t//��ǰ���Ĵ�����\nstatic struct pbuf *recv_data;\t\t//���Ķ����pbuf\n\nstruct tcp_pcb *tcp_input_pcb;\t//��ǰ���Ŀ��ƿ�\n\n/* Forward declarations. */\nstatic err_t tcp_process(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nstatic void tcp_receive(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\nstatic void tcp_parseopt(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\n\nstatic err_t tcp_listen_input(struct tcp_pcb_listen *pcb)ICACHE_FLASH_ATTR;\nstatic err_t tcp_timewait_input(struct tcp_pcb *pcb)ICACHE_FLASH_ATTR;\n\n/**\n * The initial input processing of TCP. It verifies the TCP header, demultiplexes\n * the segment between the PCBs and passes it on to tcp_process(), which implements\n * the TCP finite state machine. This function is called by the IP layer (in\n * ip_input()).\n *\n * @param p received TCP segment to process (p->payload pointing to the IP header)\n * @param inp network interface on which this segment was received\n */\n /** \n *  TCP��ʼ�����봦�?��֤��TCPͷ���������IP����� \n \n * @����p:������յ�TCP��(ָ��IPͷ�ĸ���) \n * @����inp:���նε�����ӿ� \n */ \nvoid\ntcp_input(struct pbuf *p, struct netif *inp)\n{\n  struct tcp_pcb *pcb, *prev;\n  struct tcp_pcb_listen *lpcb;\n#if SO_REUSE\n  struct tcp_pcb *lpcb_prev = NULL;\n  struct tcp_pcb_listen *lpcb_any = NULL;\n#endif /* SO_REUSE */\n  u8_t hdrlen;\n  err_t err;\n\n  PERF_START;\n\n  TCP_STATS_INC(tcp.recv);\t//״̬��1 \n  snmp_inc_tcpinsegs();\t\t\t//tcp����μ�1\n\n  iphdr = (struct ip_hdr *)p->payload;// pointer to the actual data in the buffer\n  /* \n  *��ͷ����(IHL)��4λ��IPЭ���ͷ�ĳ��ȣ�ָ��IPv4Э���ͷ���ȵ��ֽ������ٸ�32λ�� \n  *����IPv4�İ�ͷ���ܰ�ɱ������Ŀ�ѡ ���������ֶο�������ȷ��IPv4��ݱ�����ݲ��ֵ�ƫ������ \n  *IPv4��ͷ����С������20���ֽڣ����IHL����ֶε���Сֵ��ʮ���Ʊ�ʾ����5 (5x4 = 20�ֽ�)�� \n  *����˵�����ʾ�İ�ͷ�����ֽ�����4�ֽڵı���  \n  */\n  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);\n\n#if TCP_INPUT_DEBUG\n  tcp_debug_print(tcphdr);\n#endif\n\n  /* remove header from payload */\n  if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {\n    /* drop short packets */\n    LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_input: short packet (%\"U16_F\" bytes) discarded\\n\", p->tot_len));\n    TCP_STATS_INC(tcp.lenerr);//���󳤶ȼ���\n    TCP_STATS_INC(tcp.drop);//��ֹ����\n    snmp_inc_tcpinerrs();\n    pbuf_free(p);//�ͷ�buffer \n    return;\n  }\n\n  /* Don't even process incoming broadcasts/multicasts. */\n  if (ip_addr_isbroadcast(&current_iphdr_dest, inp) ||\n      ip_addr_ismulticast(&current_iphdr_dest)) {\n    TCP_STATS_INC(tcp.proterr);//Э��������\n    TCP_STATS_INC(tcp.drop);\n    snmp_inc_tcpinerrs();\n    pbuf_free(p);\n    return;\n  }\n\n#if CHECKSUM_CHECK_TCP\n  /* Verify TCP checksum. */\n  if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),\n      IP_PROTO_TCP, p->tot_len) != 0) {\n      LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_input: packet discarded due to failing checksum 0x%04\"X16_F\"\\n\",\n        inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),\n      IP_PROTO_TCP, p->tot_len)));\n#if TCP_DEBUG\n    tcp_debug_print(tcphdr);\n#endif /* TCP_DEBUG */\n    TCP_STATS_INC(tcp.chkerr);//У��������\n    TCP_STATS_INC(tcp.drop);\n    snmp_inc_tcpinerrs();\n    pbuf_free(p);\n    return;\n  }\n#endif\n\n  /* Move the payload pointer in the pbuf so that it points to the\n     TCP data instead of the TCP header. */\n  hdrlen = TCPH_HDRLEN(tcphdr);//����ͷ�ĳ���\n  if(pbuf_header(p, -(hdrlen * 4))){//���TCPͷ������0Ϊ�ɹ�������\n    /* drop short packets */\n    LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_input: short packet\\n\"));\n    TCP_STATS_INC(tcp.lenerr);//tcp���ȴ������\n    TCP_STATS_INC(tcp.drop);\n    snmp_inc_tcpinerrs();\n    pbuf_free(p);\n    return;\n  }\n\n  /* Convert fields in TCP header to host byte order. */\n  tcphdr->src = ntohs(tcphdr->src);\t\t\t\t//ת��Դ��ַ\n  tcphdr->dest = ntohs(tcphdr->dest);\t\t\t\t//ת��Ŀ�ĵ�ַ\n  seqno = tcphdr->seqno = ntohl(tcphdr->seqno);\t//ת�����к� \n  ackno = tcphdr->ackno = ntohl(tcphdr->ackno);\t//ת��Ӧ���\n  tcphdr->wnd = ntohs(tcphdr->wnd);\t\t\t\t//ת��tcp����\n\n  flags = TCPH_FLAGS(tcphdr);//�õ�tcp header�ı�־ \n  /* \n  *��־��3λ�����ֶΣ��� \n  *    ����λ��1λ \n  *    ���ֶ�λ��1λ��ȡֵ��0��������ݱ��ֶΣ���1����ݱ����ֶܷΣ� \n  *    ����λ��1λ��ȡֵ��0����ݰ����û�а�1����ݰ�����и��İ� \n  */ \n  tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);//TCP_FIN �� TCP_SYN ��λ��1�������0\n\n  /* Demultiplex an incoming segment. First, we check if it is destined\n     for an active connection. ���ȣ�����Ƿ�һ��Ҫ����һ������*/\n ////////////////////////////////////////////////////////////////////////////////////////\n  prev = NULL;  \n  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {//������б�\n    LWIP_ASSERT(\"tcp_input: active pcb->state != CLOSED\", pcb->state != CLOSED);\n    LWIP_ASSERT(\"tcp_input: active pcb->state != TIME-WAIT\", pcb->state != TIME_WAIT);\n    LWIP_ASSERT(\"tcp_input: active pcb->state != LISTEN\", pcb->state != LISTEN);\n    if (pcb->remote_port == tcphdr->src &&\n       pcb->local_port == tcphdr->dest &&\n       ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&\n       ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {//�����صĵ�ַ\n\n      /* Move this PCB to the front of the list so that subsequent\n         lookups will be faster (we exploit locality in TCP segment\n         arrivals). */\n      LWIP_ASSERT(\"tcp_input: pcb->next != pcb (before cache)\", pcb->next != pcb);\n      if (prev != NULL) {//���ǰһ���ڵ㲻Ϊ��\n        prev->next = pcb->next;\n        pcb->next = tcp_active_pcbs;\n        tcp_active_pcbs = pcb;//pcb������ǰ��\n      }\n      LWIP_ASSERT(\"tcp_input: pcb->next != pcb (after cache)\", pcb->next != pcb);\n      break;\n    }\n    prev = pcb;//prevָ��pcb\n  }\n\n  if (pcb == NULL) {\n    /* If it did not go to an active connection, we check the connections\n       in the TIME-WAIT state. */\n    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {//����ȴ�״̬�µ�pcb\n      LWIP_ASSERT(\"tcp_input: TIME-WAIT pcb->state == TIME-WAIT\", pcb->state == TIME_WAIT);\n      if (pcb->remote_port == tcphdr->src &&\n         pcb->local_port == tcphdr->dest &&\n         ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&\n         ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {\n        /* We don't really care enough to move this PCB to the front\n           of the list since we are not very likely to receive that\n           many segments for connections in TIME-WAIT. */\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_input: packed for TIME_WAITing connection.\\n\"));\n        tcp_timewait_input(pcb);//����tcp timewait �İ�\n        pbuf_free(p);\n        return;\n      }\n    }\n\n    /* Finally, if we still did not get a match, we check all PCBs that\n       are LISTENing for incoming connections. */\n    prev = NULL;\n    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {//�������״̬�����е�pcb\n      if (lpcb->local_port == tcphdr->dest) {\n#if SO_REUSE\n        if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {\n          /* found an exact match */\n          break;\n        } else if(ip_addr_isany(&(lpcb->local_ip))) {\n          /* found an ANY-match */\n          lpcb_any = lpcb;\n          lpcb_prev = prev;\n        }\n#else /* SO_REUSE */\n        if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest) ||\n            ip_addr_isany(&(lpcb->local_ip))) {\n          /* found a match */\n          break;\n        }\n#endif /* SO_REUSE */\n      }\n      prev = (struct tcp_pcb *)lpcb;\n    }\n#if SO_REUSE\n    /* first try specific local IP */\n    if (lpcb == NULL) {\n      /* only pass to ANY if no specific local IP has been found */\n      lpcb = lpcb_any;\n      prev = lpcb_prev;\n    }\n#endif /* SO_REUSE */\n    if (lpcb != NULL) {\n      /* Move this PCB to the front of the list so that subsequent\n         lookups will be faster (we exploit locality in TCP segment\n         arrivals). */\n      if (prev != NULL) {\n        ((struct tcp_pcb_listen *)prev)->next = lpcb->next;\n              /* our successor is the remainder of the listening list */\n        lpcb->next = tcp_listen_pcbs.listen_pcbs;\n              /* put this listening pcb at the head of the listening list */\n        tcp_listen_pcbs.listen_pcbs = lpcb;\n      }\n    \n      LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_input: packed for LISTENing connection.\\n\"));\n      tcp_listen_input(lpcb);//����tcp������ݰ� \n      pbuf_free(p);\n      return;\n    }\n  }\n\n#if TCP_INPUT_DEBUG\n  LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags \"));\n  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));\n  LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"-+-+-+-+-+-+-+-+-+-+-+-+-+-+\\n\"));\n#endif /* TCP_INPUT_DEBUG */\n\n\n  if (pcb != NULL) {\n    /* The incoming segment belongs to a connection. */\n#if TCP_INPUT_DEBUG\n#if TCP_DEBUG\n    tcp_debug_print_state(pcb->state);\n#endif /* TCP_DEBUG */\n#endif /* TCP_INPUT_DEBUG */\n\n    /* Set up a tcp_seg structure. */\n    inseg.next = NULL;\n    inseg.len = p->tot_len;\n    inseg.p = p;\n    inseg.tcphdr = tcphdr;\n\n    recv_data = NULL;\n    recv_flags = 0;\n\n    /* If there is data which was previously \"refused\" by upper layer */\n    if (pcb->refused_data != NULL) {\n      /* Notify again application with data previously received. */\n      LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_input: notify kept packet\\n\"));\n      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);//pcb�������\n      if (err == ERR_OK) {\n        pcb->refused_data = NULL;\n      } else if ((err == ERR_ABRT) || (tcplen > 0)) {\n        /* if err == ERR_ABRT, 'pcb' is already deallocated */\n        /* Drop incoming packets because pcb is \"full\" (only if the incoming\n           segment contains data). */\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_input: drop incoming packets, because pcb is \\\"full\\\"\\n\"));\n        TCP_STATS_INC(tcp.drop);//tcp�������\n        snmp_inc_tcpinerrs();\n        pbuf_free(p);\n        return;\n      }\n    }\n    tcp_input_pcb = pcb;//��¼��ǰ���Ĵ���Ŀ��ƿ�\n    err = tcp_process(pcb);//���?��\n    /* A return value of ERR_ABRT means that tcp_abort() was called\n       and that the pcb has been freed. If so, we don't do anything. */\n    if (err != ERR_ABRT) {\n      if (recv_flags & TF_RESET) {\n        /* TF_RESET means that the connection was reset by the other\n           end. We then call the error callback to inform the\n           application that the connection is dead before we\n           deallocate the PCB. */\n        TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);\n        tcp_pcb_remove(&tcp_active_pcbs, pcb);//ɾ���pcb�б��е�pcb\n        memp_free(MEMP_TCP_PCB, pcb);\n      } else if (recv_flags & TF_CLOSED) {\n        /* The connection has been closed and we will deallocate the\n           PCB. */\n        if (!(pcb->flags & TF_RXCLOSED)) {\n          /* Connection closed although the application has only shut down the\n             tx side: call the PCB's err callback and indicate the closure to\n             ensure the application doesn't continue using the PCB. */\n          TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD);\n        }\n        tcp_pcb_remove(&tcp_active_pcbs, pcb);\n        memp_free(MEMP_TCP_PCB, pcb);\n      } else {\n        err = ERR_OK;\n        /* If the application has registered a \"sent\" function to be\n           called when new send buffer space is available, we call it\n           now. */\n        if (pcb->acked > 0) {\n          TCP_EVENT_SENT(pcb, pcb->acked, err);//����ݱ�ȷ�ϣ��ص��û���send����\n          if (err == ERR_ABRT) {\n            goto aborted;\n          }\n        }\n\n        if (recv_data != NULL) {//����ݽ��յ�\n          LWIP_ASSERT(\"pcb->refused_data == NULL\", pcb->refused_data == NULL);\n          if (pcb->flags & TF_RXCLOSED) {\n            /* received data although already closed -> abort (send RST) to\n               notify the remote host that not all data has been processed */\n            pbuf_free(recv_data);\n            tcp_abort(pcb);\n            goto aborted;\n          }\n\n\t//PSH��־ PSH ����λ��\n\t//��PSH=1ʱ��Ҫ���ͷ����Ϸ��͸÷ֶΣ�\n\t//����շ�����Ľ����Ľ���Ӧ�ò㣬�������д��?\n\t\t  \n          if (flags & TCP_PSH) {\n            recv_data->flags |= PBUF_FLAG_PUSH;//���bufferӦ������������\n          }\n\n          /* Notify application that data has been received. */\n          TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);\n          if (err == ERR_ABRT) {\n            goto aborted;\n          }\n\n          /* If the upper layer can't receive this data, store it */\n          if (err != ERR_OK) {\n            pcb->refused_data = recv_data;\n            LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_input: keep incoming packet, because pcb is \\\"full\\\"\\n\"));\n          }\n        }\n\n        /* If a FIN segment was received, we call the callback\n           function with a NULL buffer to indicate EOF. */\n        if (recv_flags & TF_GOT_FIN) {\n          /* correct rcv_wnd as the application won't call tcp_recved()\n             for the FIN's seqno */\n          if (pcb->rcv_wnd != TCP_WND) {\n            pcb->rcv_wnd++;\n          }\n\t \n          TCP_EVENT_CLOSED(pcb, err);\n          if (err == ERR_ABRT) {\n            goto aborted;\n          }\n        }\n\n        tcp_input_pcb = NULL;//���ȫ�ֱ���\n        /* Try to send something out. */\n        tcp_output(pcb);//�����������\n#if TCP_INPUT_DEBUG\n#if TCP_DEBUG\n        tcp_debug_print_state(pcb->state);\n#endif /* TCP_DEBUG */\n#endif /* TCP_INPUT_DEBUG */\n      }\n    }\n    /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).\n       Below this line, 'pcb' may not be dereferenced! */\naborted:\n    tcp_input_pcb = NULL;\n    recv_data = NULL;\n\n    /* give up our reference to inseg.p */\n    if (inseg.p != NULL)\n    {\n      pbuf_free(inseg.p);//�ͷ�buffer\n      inseg.p = NULL;\n    }\n\n    /*add processing queue segments that arrive out of order by LiuHan*/\n#if TCP_QUEUE_OOSEQ\n    extern char RxNodeNum(void);\n    if (RxNodeNum() < 2){\n    \textern void pbuf_free_ooseq_new(void* arg);\n//    \tos_printf(\"reclaim some memory from queued\\n\");\n    \tpbuf_free_ooseq_new(NULL);\n    }\n#endif\n  } else {\n\n    /* If no matching PCB was found, send a TCP RST (reset) to the\n       sender. */\n    LWIP_DEBUGF(TCP_RST_DEBUG, (\"tcp_input: no PCB match found, resetting.\\n\"));\n    if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {\n      TCP_STATS_INC(tcp.proterr);//Э��������\n      TCP_STATS_INC(tcp.drop);//tcp�������\n      tcp_rst(ackno, seqno + tcplen,\n        ip_current_dest_addr(), ip_current_src_addr(),\n        tcphdr->dest, tcphdr->src);//����TCP��λ\n    }\n    pbuf_free(p);\n  }\n\n  LWIP_ASSERT(\"tcp_input: tcp_pcbs_sane()\", tcp_pcbs_sane());\n  PERF_STOP(\"tcp_input\");\n}\n\n/**\n * Called by tcp_input() when a segment arrives for a listening\n * connection (from tcp_input()).\n *\n * @param pcb the tcp_pcb_listen for which a segment arrived\n * @return ERR_OK if the segment was processed\n *         another err_t on error\n *\n * @note the return value is not (yet?) used in tcp_input()\n * @note the segment which arrived is saved in global variables, therefore only the pcb\n *       involved is passed as a parameter to this function\n */\n /*\n*����LISTEN״̬�Ŀ��ƿ���øú���\n*ͨ���Ƿ�������������һ���˿ڲ�����ͻ���SYN��������\n*\n*/\nstatic err_t\ntcp_listen_input(struct tcp_pcb_listen *pcb)\n{\n  struct tcp_pcb *npcb;\n  struct tcp_pcb *pactive_pcb;\n  u8_t active_pcb_num = 0;\n  err_t rc;\n\n  /* In the LISTEN state, we check for incoming SYN segments,\n     creates a new PCB, and responds with a SYN|ACK. */\n  if (flags & TCP_ACK) {\n    /* For incoming segments with the ACK flag set, respond with a\n       RST. */\n    LWIP_DEBUGF(TCP_RST_DEBUG, (\"tcp_listen_input: ACK in LISTEN, sending reset\\n\"));\n    tcp_rst(ackno + 1, seqno + tcplen,\n      ip_current_dest_addr(), ip_current_src_addr(),\n      tcphdr->dest, tcphdr->src);\n  } else if (flags & TCP_SYN) {//�յ�SYN����\n    LWIP_DEBUGF(TCP_DEBUG, (\"TCP connection request %\"U16_F\" -> %\"U16_F\".\\n\", tcphdr->src, tcphdr->dest));\n#if TCP_LISTEN_BACKLOG\n    if (pcb->accepts_pending >= pcb->backlog) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_listen_input: listen backlog exceeded for port %\"U16_F\"\\n\", tcphdr->dest));\n      return ERR_ABRT;\n    }\n#endif /* TCP_LISTEN_BACKLOG */\n    for(pactive_pcb = tcp_active_pcbs; pactive_pcb != NULL; pactive_pcb = pactive_pcb->next)\n    \tactive_pcb_num ++;\n    if (active_pcb_num == MEMP_NUM_TCP_PCB){\n    \tLWIP_DEBUGF(TCP_DEBUG, (\"tcp_listen_input: exceed the number of active TCP connections\\n\"));\n    \tTCP_STATS_INC(tcp.memerr);\n    \treturn ERR_MEM;\n    }\n    npcb = tcp_alloc(pcb->prio);//�������ƿ�\n    /* If a new PCB could not be created (probably due to lack of memory),\n       we don't do anything, but rely on the sender will retransmit the\n       SYN at a time when we have more memory available. */\n    if (npcb == NULL) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_listen_input: could not allocate PCB\\n\"));\n      TCP_STATS_INC(tcp.memerr);//TCP�ڴ�������\n      return ERR_MEM;\n    }\n\n#if TCP_LISTEN_BACKLOG\n    pcb->accepts_pending++;\n#endif /* TCP_LISTEN_BACKLOG */\n    /* Set up the new PCB. */\n    //���ƿ���������ص�4���ֶ�\n    ip_addr_copy(npcb->local_ip, current_iphdr_dest);\n    npcb->local_port = pcb->local_port;\n    ip_addr_copy(npcb->remote_ip, current_iphdr_src);\n    npcb->remote_port = tcphdr->src;\n\n\t//���ƿ��������ֶ�\n    npcb->state = SYN_RCVD;//��������״̬\n    npcb->rcv_nxt = seqno + 1;//������һ������������\n    npcb->rcv_ann_right_edge = npcb->rcv_nxt;\n    npcb->snd_wnd = tcphdr->wnd;//���÷��ʹ���\n    npcb->ssthresh = npcb->snd_wnd;\n    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */\n    npcb->callback_arg = pcb->callback_arg;\n#if LWIP_CALLBACK_API\n    npcb->accept = pcb->accept;\n#endif /* LWIP_CALLBACK_API */\n    /* inherit socket options */\n    npcb->so_options = pcb->so_options & SOF_INHERITED;\n    /* Register the new PCB so that we can begin receiving segments\n       for it. */\n    TCP_REG(&tcp_active_pcbs, npcb);\n\n    /* Parse any options in the SYN. */\n    tcp_parseopt(npcb);\n#if TCP_CALCULATE_EFF_SEND_MSS\n    npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));\n#endif /* TCP_CALCULATE_EFF_SEND_MSS */\n\n    snmp_inc_tcppassiveopens();\n\n    /* Send a SYN|ACK together with the MSS option. */\n    rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);\n    if (rc != ERR_OK) {//��������ͷ��¿��ƿ�\n      tcp_abandon(npcb, 0);\n      return rc;\n    }\n    return tcp_output(npcb);//���ͱ���\n  }\n  return ERR_OK;\n}\n\n/**\n * Called by tcp_input() when a segment arrives for a connection in\n * TIME_WAIT.\n *\n * @param pcb the tcp_pcb for which a segment arrived\n *\n * @note the segment which arrived is saved in global variables, therefore only the pcb\n *       involved is passed as a parameter to this function\n */\n /*\n*����TIME_WAIT״̬�Ŀ��ƿ���øú������յ��ı��ĶΣ�\n*��״̬�£��ر����ӵ����ֹ���Ѿ��������ڵȴ�2MSL��ʱ��\n*��״̬�µı��Ķ����������еľ���ݣ�ֱ��ɾ��ɡ�\n*����Ҫ���ͷ�����ACK����\n*/\nstatic err_t\ntcp_timewait_input(struct tcp_pcb *pcb)\n{\n  \n  if (flags & TCP_RST)  {\t\t//RST��λ��ֱ�ӷ���\n    return ERR_OK;\n  }\n \n  if (flags & TCP_SYN) {\t\t//��SYN������Ϣ����������ݱ���ڽ��մ����ڣ����ͷ�����RST����\n \n    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {\n      \n      tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),\n        tcphdr->dest, tcphdr->src);\n      return ERR_OK;\n    }\n  } else if (flags & TCP_FIN) {\t//���İ�FIN������Ϣ\n  \t\t\t\t\t\t    \n    pcb->tmr = tcp_ticks;\t\t  \t//��λ�ȴ�2MSLʱ�䣬���ƿ����µȴ�2MSL\n  }\n\n  if ((tcplen > 0))  {\t\t\t\t//��������ݵı��Ļ����ڽ��մ������SYN����\n    pcb->flags |= TF_ACK_NOW;//����һ��ACK����\n    return tcp_output(pcb);\n  }\n  return ERR_OK;\n}\n\n/**\n * Implements the TCP state machine. Called by tcp_input. In some\n * states tcp_receive() is called to receive data. The tcp_seg\n * argument will be freed by the caller (tcp_input()) unless the\n * recv_data pointer in the pcb is set.\n *\n * @param pcb the tcp_pcb for which a segment arrived\n *\n * @note the segment which arrived is saved in global variables, therefore only the pcb\n *       involved is passed as a parameter to this function\n */\nstatic err_t\ntcp_process(struct tcp_pcb *pcb)\n{\n  struct tcp_seg *rseg;\n  u8_t acceptable = 0;\n  err_t err;\n\n  err = ERR_OK;\n\n  /* Process incoming RST segments. */\n  if (flags & TCP_RST) {\n    /* First, determine if the reset is acceptable. */\n    if (pcb->state == SYN_SENT) {\n      if (ackno == pcb->snd_nxt) {\n        acceptable = 1;\n      }\n    } else {\n      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, \n                          pcb->rcv_nxt+pcb->rcv_wnd)) {\n        acceptable = 1;\n      }\n    }\n\n    if (acceptable) {\n      LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_process: Connection RESET\\n\"));\n      LWIP_ASSERT(\"tcp_input: pcb->state != CLOSED\", pcb->state != CLOSED);\n      recv_flags |= TF_RESET;\n      pcb->flags &= ~TF_ACK_DELAY;\n      return ERR_RST;\n    } else {\n      LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_process: unacceptable reset seqno %\"U32_F\" rcv_nxt %\"U32_F\"\\n\",\n       seqno, pcb->rcv_nxt));\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_process: unacceptable reset seqno %\"U32_F\" rcv_nxt %\"U32_F\"\\n\",\n       seqno, pcb->rcv_nxt));\n      return ERR_OK;\n    }\n  }\n\n  if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { \n    /* Cope with new connection attempt after remote end crashed */\n    tcp_ack_now(pcb);\n    return ERR_OK;\n  }\n  \n  if ((pcb->flags & TF_RXCLOSED) == 0) {\n    /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */\n    pcb->tmr = tcp_ticks;\n  }\n  pcb->keep_cnt_sent = 0;\n\n  tcp_parseopt(pcb);\n\n  /* Do different things depending on the TCP state. */\n  switch (pcb->state) {\n  case SYN_SENT:\n    LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"SYN-SENT: ackno %\"U32_F\" pcb->snd_nxt %\"U32_F\" unacked %\"U32_F\"\\n\", ackno,\n     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));\n    /* received SYN ACK with expected sequence number? */\n    if ((flags & TCP_ACK) && (flags & TCP_SYN)\n        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {\n      pcb->snd_buf++;\n      pcb->rcv_nxt = seqno + 1;\n      pcb->rcv_ann_right_edge = pcb->rcv_nxt;\n      pcb->lastack = ackno;\n      pcb->snd_wnd = tcphdr->wnd;\n      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */\n      pcb->state = ESTABLISHED;\n\n#if TCP_CALCULATE_EFF_SEND_MSS\n      pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));\n#endif /* TCP_CALCULATE_EFF_SEND_MSS */\n\n      /* Set ssthresh again after changing pcb->mss (already set in tcp_connect\n       * but for the default value of pcb->mss) */\n      pcb->ssthresh = pcb->mss * 10;\n\n      pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);\n      LWIP_ASSERT(\"pcb->snd_queuelen > 0\", (pcb->snd_queuelen > 0));\n      --pcb->snd_queuelen;\n      LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"tcp_process: SYN-SENT --queuelen %\"U16_F\"\\n\", (u16_t)pcb->snd_queuelen));\n      rseg = pcb->unacked;\n      pcb->unacked = rseg->next;\n\n      /* If there's nothing left to acknowledge, stop the retransmit\n         timer, otherwise reset it to start again */\n      if(pcb->unacked == NULL)\n        pcb->rtime = -1;\n      else {\n        pcb->rtime = 0;\n        pcb->nrtx = 0;\n      }\n\n      tcp_seg_free(rseg);\n\n      /* Call the user specified function to call when sucessfully\n       * connected. */\n      TCP_EVENT_CONNECTED(pcb, ERR_OK, err);\n      if (err == ERR_ABRT) {\n        return ERR_ABRT;\n      }\n      tcp_ack_now(pcb);\n    }\n    /* received ACK? possibly a half-open connection */\n    else if (flags & TCP_ACK) {\n      /* send a RST to bring the other side in a non-synchronized state. */\n      tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),\n        tcphdr->dest, tcphdr->src);\n    }\n    break;\n  case SYN_RCVD:\n    if (flags & TCP_ACK) {\n      /* expected ACK number? */\n      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {\n        u16_t old_cwnd;\n        pcb->state = ESTABLISHED;\n        LWIP_DEBUGF(TCP_DEBUG, (\"TCP connection established %\"U16_F\" -> %\"U16_F\".\\n\", inseg.tcphdr->src, inseg.tcphdr->dest));\n#if LWIP_CALLBACK_API\n        LWIP_ASSERT(\"pcb->accept != NULL\", pcb->accept != NULL);\n#endif\n        /* Call the accept function. */\n        TCP_EVENT_ACCEPT(pcb, ERR_OK, err);\n        if (err != ERR_OK) {\n          /* If the accept function returns with an error, we abort\n           * the connection. */\n          /* Already aborted? */\n          if (err != ERR_ABRT) {\n            tcp_abort(pcb);\n          }\n          return ERR_ABRT;\n        }\n        old_cwnd = pcb->cwnd;\n        /* If there was any data contained within this ACK,\n         * we'd better pass it on to the application as well. */\n        tcp_receive(pcb);\n\n        /* Prevent ACK for SYN to generate a sent event */\n        if (pcb->acked != 0) {\n          pcb->acked--;\n        }\n\n        pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);\n\n        if (recv_flags & TF_GOT_FIN) {\n          tcp_ack_now(pcb);\n          pcb->state = CLOSE_WAIT;\n        }\n      } else {\n        /* incorrect ACK number, send RST */\n        tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),\n                tcphdr->dest, tcphdr->src);\n      }\n    } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {\n      /* Looks like another copy of the SYN - retransmit our SYN-ACK */\n      tcp_rexmit(pcb);\n    }\n    break;\n  case CLOSE_WAIT:\n    /* FALLTHROUGH */\n  case ESTABLISHED:\n    tcp_receive(pcb);\n    if (recv_flags & TF_GOT_FIN) { /* passive close */\n      tcp_ack_now(pcb);\n      pcb->state = CLOSE_WAIT;\n    }\n    break;\n  case FIN_WAIT_1:\n    tcp_receive(pcb);\n    if (recv_flags & TF_GOT_FIN) {\n      if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {\n        LWIP_DEBUGF(TCP_DEBUG,\n          (\"TCP connection closed: FIN_WAIT_1 %\"U16_F\" -> %\"U16_F\".\\n\", inseg.tcphdr->src, inseg.tcphdr->dest));\n        tcp_ack_now(pcb);\n        tcp_pcb_purge(pcb);\n        TCP_RMV(&tcp_active_pcbs, pcb);\n        pcb->state = TIME_WAIT;\n        TCP_REG(&tcp_tw_pcbs, pcb);\n      } else {\n        tcp_ack_now(pcb);\n        pcb->state = CLOSING;\n      }\n    } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {\n      pcb->state = FIN_WAIT_2;\n    }\n    break;\n  case FIN_WAIT_2:\n    tcp_receive(pcb);\n    if (recv_flags & TF_GOT_FIN) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"TCP connection closed: FIN_WAIT_2 %\"U16_F\" -> %\"U16_F\".\\n\", inseg.tcphdr->src, inseg.tcphdr->dest));\n      tcp_ack_now(pcb);\n      tcp_pcb_purge(pcb);\n      TCP_RMV(&tcp_active_pcbs, pcb);\n      pcb->state = TIME_WAIT;\n      TCP_REG(&tcp_tw_pcbs, pcb);\n    }\n    break;\n  case CLOSING:\n    tcp_receive(pcb);\n    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"TCP connection closed: CLOSING %\"U16_F\" -> %\"U16_F\".\\n\", inseg.tcphdr->src, inseg.tcphdr->dest));\n      tcp_pcb_purge(pcb);\n      TCP_RMV(&tcp_active_pcbs, pcb);\n      pcb->state = TIME_WAIT;\n      TCP_REG(&tcp_tw_pcbs, pcb);\n    }\n    break;\n  case LAST_ACK:\n    tcp_receive(pcb);\n    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"TCP connection closed: LAST_ACK %\"U16_F\" -> %\"U16_F\".\\n\", inseg.tcphdr->src, inseg.tcphdr->dest));\n      /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */\n      recv_flags |= TF_CLOSED;\n    }\n    break;\n  default:\n    break;\n  }\n  return ERR_OK;\n}\n\n#if TCP_QUEUE_OOSEQ\n/**\n * Insert segment into the list (segments covered with new one will be deleted)\n *\n * Called from tcp_receive()\n */\nstatic void ICACHE_FLASH_ATTR\ntcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)\n{\n  struct tcp_seg *old_seg;\n\n  if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {\n    /* received segment overlaps all following segments */\n    tcp_segs_free(next);\n    next = NULL;\n  }\n  else {\n    /* delete some following segments\n       oos queue may have segments with FIN flag */\n    while (next &&\n           TCP_SEQ_GEQ((seqno + cseg->len),\n                      (next->tcphdr->seqno + next->len))) {\n      /* cseg with FIN already processed */\n      if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {\n        TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);\n      }\n      old_seg = next;\n      next = next->next;\n      tcp_seg_free(old_seg);\n    }\n    if (next &&\n        TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {\n      /* We need to trim the incoming segment. */\n      cseg->len = (u16_t)(next->tcphdr->seqno - seqno);\n      pbuf_realloc(cseg->p, cseg->len);\n    }\n  }\n  cseg->next = next;\n}\n#endif /* TCP_QUEUE_OOSEQ */\n\n/**\n * Called by tcp_process. Checks if the given segment is an ACK for outstanding\n * data, and if so frees the memory of the buffered data. Next, is places the\n * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment\n * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until\n * i it has been removed from the buffer.\n *\n * If the incoming segment constitutes an ACK for a segment that was used for RTT\n * estimation, the RTT is estimated here as well.\n *\n * Called from tcp_process().\n */\nstatic void\ntcp_receive(struct tcp_pcb *pcb)\n{\n  struct tcp_seg *next;\n#if TCP_QUEUE_OOSEQ\n  struct tcp_seg *prev, *cseg;\n#endif /* TCP_QUEUE_OOSEQ */\n  struct pbuf *p;\n  s32_t off;\n  s16_t m;\n  u32_t right_wnd_edge;\n  u16_t new_tot_len;\n  int found_dupack = 0;\n\n  if (flags & TCP_ACK) {//���İ�ACK\n    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;//���ʹ��� + ����Ӧ����󴰿ڸ���\n\n    // first /* Update window. */\n    /*seqno > snd_wl1���������ֹ�̲��ô��ָ���;\n    *seqno = snd_wl1����ackno > snd_wl2;��ʱ���Է�û�з�����ݣ�ֻ���յ���ݵ�ȷ��;\n    *ackno = snd_wl2�ұ����ײ��б�snd_wnd���Ĵ���.����������Ӧֵ\n    */\n    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||\n       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||\n       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {\n      pcb->snd_wnd = tcphdr->wnd;\n      pcb->snd_wl1 = seqno;\n      pcb->snd_wl2 = ackno;\n      if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {\n          pcb->persist_backoff = 0;//�����ʱ���˳�\n      }\n      LWIP_DEBUGF(TCP_WND_DEBUG, (\"tcp_receive: window update %\"U16_F\"\\n\", pcb->snd_wnd));\n#if TCP_WND_DEBUG\n    } else {\n      if (pcb->snd_wnd != tcphdr->wnd) {\n        LWIP_DEBUGF(TCP_WND_DEBUG, \n                    (\"tcp_receive: no window update lastack %\"U32_F\" ackno %\"\n                     U32_F\" wl1 %\"U32_F\" seqno %\"U32_F\" wl2 %\"U32_F\"\\n\",\n                     pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));\n      }\n#endif /* TCP_WND_DEBUG */\n    }\n\n    /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a\n     * duplicate ack if:\n     * 1) It doesn't ACK new data û��ȷ�������\n     * 2) length of received packet is zero (i.e. no payload) ���Ķ����κ����\n     * 3) the advertised window hasn't changed ���ش���û�и���\n     * 4) There is outstanding unacknowledged data (retransmission timer running)������ݵȴ�ȷ��\n     * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)   ackno = lastack\n     * \n     * If it passes all five, should process as a dupack: \n     * a) dupacks < 3: do nothing \n     * b) dupacks == 3: fast retransmit \n     * c) dupacks > 3: increase cwnd \n     * \n     * If it only passes 1-3, should reset dupack counter (and add to\n     * stats, which we don't do in lwIP)\n     *\n     * If it only passes 1, should reset dupack counter\n     *\n     */\n\n    /* Clause 1 */\n    if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {//���ظ�ACK?\n      pcb->acked = 0;\n      /* Clause 2 */\n      if (tcplen == 0) {\n        /* Clause 3 */\n        if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){\n          /* Clause 4 */\n          if (pcb->rtime >= 0) {\n            /* Clause 5 */\n            if (pcb->lastack == ackno) {\n              found_dupack = 1;\n              if (pcb->dupacks + 1 > pcb->dupacks)\n                ++pcb->dupacks;\n              if (pcb->dupacks > 3) {\n                /* Inflate the congestion window, but not if it means that\n                   the value overflows. */\n                if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {\n                  pcb->cwnd += pcb->mss;\n                }\n              } else if (pcb->dupacks == 3) {//���ظ�ACK\n                /* Do fast retransmit */\n                tcp_rexmit_fast(pcb);\n              }\n            }\n          }\n        }\n      }\n      /* If Clause (1) or more is true, but not a duplicate ack, reset\n       * count of consecutive duplicate acks */\n      if (!found_dupack) {\n        pcb->dupacks = 0;\n      }\n    } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){//ackno��lastack+1��snd_nxt֮�䣬�жϷ��ʹ��������\n      /* We come here when the ACK acknowledges new data. */\n\t  \n      if (pcb->flags & TF_INFR) {\n        pcb->flags &= ~TF_INFR;// Reset the \"IN Fast Retransmit\" flag,since we are no longer in fast retransmit\n        pcb->cwnd = pcb->ssthresh;//Reset the congestion window to the  \"slow start threshold\".       \n      }\n\n      /* Reset the number of retransmissions. */\n      pcb->nrtx = 0;\n\n      /* Reset the retransmission time-out. */\n      pcb->rto = (pcb->sa >> 3) + pcb->sv;\n\n      /* Update the send buffer space. Diff between the two can never exceed 64K? */\n      pcb->acked = (u16_t)(ackno - pcb->lastack);\n\n      pcb->snd_buf += pcb->acked;\n\n      /* Reset the fast retransmit variables. */\n      pcb->dupacks = 0;\n      pcb->lastack = ackno;\n\n      /* Update the congestion control variables (cwnd and\n         ssthresh). */\n      if (pcb->state >= ESTABLISHED) {//״̬Ϊ�������ӱ�־\n        if (pcb->cwnd < pcb->ssthresh) {\n          if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {\n            pcb->cwnd += pcb->mss;\n          }\n          LWIP_DEBUGF(TCP_CWND_DEBUG, (\"tcp_receive: slow start cwnd %\"U16_F\"\\n\", pcb->cwnd));\n        } else {\n          u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);\n          if (new_cwnd > pcb->cwnd) {\n            pcb->cwnd = new_cwnd;\n          }\n          LWIP_DEBUGF(TCP_CWND_DEBUG, (\"tcp_receive: congestion avoidance cwnd %\"U16_F\"\\n\", pcb->cwnd));\n        }\n      }\n      LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_receive: ACK for %\"U32_F\", unacked->seqno %\"U32_F\":%\"U32_F\"\\n\",\n                                    ackno,\n                                    pcb->unacked != NULL?\n                                    ntohl(pcb->unacked->tcphdr->seqno): 0,\n                                    pcb->unacked != NULL?\n                                    ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));\n\n      /* Remove segment from the unacknowledged list if the incoming\n         ACK acknowlegdes them. \n         *�ͷ�unacked�����ϱ�ȷ�ϵı��ĶΣ�\n         *ֱ��unacked����Ϊ��ֹͣ*/\n      while (pcb->unacked != NULL &&\n             TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +\n                         TCP_TCPLEN(pcb->unacked), ackno)) {\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_receive: removing %\"U32_F\":%\"U32_F\" from pcb->unacked\\n\",\n                                      ntohl(pcb->unacked->tcphdr->seqno),\n                                      ntohl(pcb->unacked->tcphdr->seqno) +\n                                      TCP_TCPLEN(pcb->unacked)));\n\n        next = pcb->unacked;//pcb unacked��־\n        pcb->unacked = pcb->unacked->next;//pcb unacked ��һ����־\n\n        LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"tcp_receive: queuelen %\"U16_F\" ... \", (u16_t)pcb->snd_queuelen));\n        LWIP_ASSERT(\"pcb->snd_queuelen >= pbuf_clen(next->p)\", (pcb->snd_queuelen >= pbuf_clen(next->p)));\n        /* Prevent ACK for FIN to generate a sent event */\n        if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {\n          pcb->acked--;\n        }\n\n        pcb->snd_queuelen -= pbuf_clen(next->p);//�������������pbufs���� \n        tcp_seg_free(next);//�ͷ�tcp��\n\n        LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"%\"U16_F\" (after freeing unacked)\\n\", (u16_t)pcb->snd_queuelen));\n        if (pcb->snd_queuelen != 0) {\n          LWIP_ASSERT(\"tcp_receive: valid queue length\", pcb->unacked != NULL ||\n                      pcb->unsent != NULL);\n        }\n      }\n\n      /* If there's nothing left to acknowledge, stop the retransmit\n         timer, otherwise reset it to start again */\n      if(pcb->unacked == NULL)\t//����ݵȴ�ȷ��\n        pcb->rtime = -1;\t\t\t//ֹͣ�ش���ʱ��\n      else\n        pcb->rtime = 0;\t\t\t//��λ�ش���ʱ��\n\n      pcb->polltmr = 0;\n    } else {\n      /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */\n      pcb->acked = 0;\n    }\n\n    /* We go through the ->unsent list to see if any of the segments\n       on the list are acknowledged by the ACK. This may seem\n       strange since an \"unsent\" segment shouldn't be acked. The\n       rationale is that lwIP puts all outstanding segments on the\n       ->unsent list after a retransmission, so these segments may\n       in fact have been sent once. */\n       /** unsent�������Ƿ��ܱ�acknoȷ�ϵı��ĶΣ������ͷ�**/\n    while (pcb->unsent != NULL &&\n           TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + \n                           TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {\n      LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_receive: removing %\"U32_F\":%\"U32_F\" from pcb->unsent\\n\",\n                                    ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +\n                                    TCP_TCPLEN(pcb->unsent)));\n\n      next = pcb->unsent;//pcbδ���ͱ�־ \n      pcb->unsent = pcb->unsent->next;//δ���͵���һ��\n      LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"tcp_receive: queuelen %\"U16_F\" ... \", (u16_t)pcb->snd_queuelen));\n      LWIP_ASSERT(\"pcb->snd_queuelen >= pbuf_clen(next->p)\", (pcb->snd_queuelen >= pbuf_clen(next->p)));\n      /* Prevent ACK for FIN to generate a sent event */\n      if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {\n        pcb->acked--;\n      }\n      pcb->snd_queuelen -= pbuf_clen(next->p);//������pbuf�ĸ���\n      tcp_seg_free(next);//�ͷŶ�\n      LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"%\"U16_F\" (after freeing unsent)\\n\", (u16_t)pcb->snd_queuelen));\n      if (pcb->snd_queuelen != 0) {//�������г���\n        LWIP_ASSERT(\"tcp_receive: valid queue length\",\n          pcb->unacked != NULL || pcb->unsent != NULL);\n      }\n    }\n    /* End of ACK for new data processing. */\n\n    LWIP_DEBUGF(TCP_RTO_DEBUG, (\"tcp_receive: pcb->rttest %\"U32_F\" rtseq %\"U32_F\" ackno %\"U32_F\"\\n\",\n                                pcb->rttest, pcb->rtseq, ackno));\n\n    /* RTT estimation calculations. This is done by checking if the\n       incoming segment acknowledges the segment we use to take a\n       round-trip time measurement. */\n    if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {//RTT���ڽ����Ҹñ��Ķα�ȷ��\n      /* diff between this shouldn't exceed 32K since this are tcp timer ticks\n         and a round-trip shouldn't be that long... */\n      m = (s16_t)(tcp_ticks - pcb->rttest);//����Mֵ\n\n      LWIP_DEBUGF(TCP_RTO_DEBUG, (\"tcp_receive: experienced rtt %\"U16_F\" ticks (%\"U16_F\" msec).\\n\",\n                                  m, m * TCP_SLOW_INTERVAL));\n\n      /* This is taken directly from VJs original code in his paper �����RTT���㹫ʽ*/\n      m = m - (pcb->sa >> 3);\n      pcb->sa += m;\n      if (m < 0) {\n        m = -m;\n      }\n      m = m - (pcb->sv >> 2);\n      pcb->sv += m;\n      pcb->rto = (pcb->sa >> 3) + pcb->sv;\n\n      LWIP_DEBUGF(TCP_RTO_DEBUG, (\"tcp_receive: RTO %\"U16_F\" (%\"U16_F\" milliseconds)\\n\",\n                                  pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));\n\n      pcb->rttest = 0;\n    }\n  }\n\n  /* If the incoming segment contains data, we must process it\n     further. */\n  if (tcplen > 0) {\n    /* This code basically does three things:\n\n    +) If the incoming segment contains data that is the next\n    in-sequence data, this data is passed to the application. This\n    might involve trimming the first edge of the data. The rcv_nxt\n    variable and the advertised window are adjusted.\n\n    +) If the incoming segment has data that is above the next\n    sequence number expected (->rcv_nxt), the segment is placed on\n    the ->ooseq queue. This is done by finding the appropriate\n    place in the ->ooseq queue (which is ordered by sequence\n    number) and trim the segment in both ends if needed. An\n    immediate ACK is sent to indicate that we received an\n    out-of-sequence segment.\n\n    +) Finally, we check if the first segment on the ->ooseq queue\n    now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If\n    rcv_nxt > ooseq->seqno, we must trim the first edge of the\n    segment on ->ooseq before we adjust rcv_nxt. The data in the\n    segments that are now on sequence are chained onto the\n    incoming segment so that we only need to call the application\n    once.\n    */\n\n    /* First, we check if we must trim the first edge. We have to do\n       this if the sequence number of the incoming segment is less\n       than rcv_nxt, and the sequence number plus the length of the\n       segment is larger than rcv_nxt. */\n    /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){\n          if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/\n    if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){// seqno < rcv_nxt < seqno + tcplen\n      /* Trimming the first edge is done by pushing the payload\n         pointer in the pbuf downwards. This is somewhat tricky since\n         we do not want to discard the full contents of the pbuf up to\n         the new starting point of the data since we have to keep the\n         TCP header which is present in the first pbuf in the chain.\n\n         What is done is really quite a nasty hack: the first pbuf in\n         the pbuf chain is pointed to by inseg.p. Since we need to be\n         able to deallocate the whole pbuf, we cannot change this\n         inseg.p pointer to point to any of the later pbufs in the\n         chain. Instead, we point the ->payload pointer in the first\n         pbuf to data in one of the later pbufs. We also set the\n         inseg.data pointer to point to the right place. This way, the\n         ->p pointer will still point to the first pbuf, but the\n         ->p->payload pointer will point to data in another pbuf.\n\n         After we are done with adjusting the pbuf pointers we must\n         adjust the ->data pointer in the seg and the segment\n         length.*/\n\t//ȥ�����Ķ�����ݱ�ŵ���rcv_nxt�����\n      off = pcb->rcv_nxt - seqno;\n      p = inseg.p;\n      LWIP_ASSERT(\"inseg.p != NULL\", inseg.p);\n      LWIP_ASSERT(\"insane offset!\", (off < 0x7fff));\n      if (inseg.p->len < off) {\n        LWIP_ASSERT(\"pbuf too short!\", (((s32_t)inseg.p->tot_len) >= off));\n        new_tot_len = (u16_t)(inseg.p->tot_len - off);\n        while (p->len < off) {\n          off -= p->len;\n          /* KJM following line changed (with addition of new_tot_len var)\n             to fix bug #9076\n             inseg.p->tot_len -= p->len; */\n          p->tot_len = new_tot_len;\n          p->len = 0;\n          p = p->next;\n        }\n        if(pbuf_header(p, (s16_t)-off)) {\n          /* Do we need to cope with this failing?  Assert for now */\n          LWIP_ASSERT(\"pbuf_header failed\", 0);\n        }\n      } else {\n        if(pbuf_header(inseg.p, (s16_t)-off)) {\n          /* Do we need to cope with this failing?  Assert for now */\n          LWIP_ASSERT(\"pbuf_header failed\", 0);\n        }\n      }\n      inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);\n      inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;\n    }\n    else {\n      if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){//seqno < rcv_nxt\n        /* the whole segment is < rcv_nxt */\n        /* must be a duplicate of a packet that has already been correctly handled */\n\t//���Ķ���������ݱ�ž�С��rcv_nxt����˱������ظ����ģ�\n\t//ֱ����Դ����ӦACK���Ĵ���\n\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_receive: duplicate seqno %\"U32_F\"\\n\", seqno));\n        tcp_ack_now(pcb);\n      }\n    }\n\n    /* The sequence number must be within the window (above rcv_nxt\n       and below rcv_nxt + rcv_wnd) in order to be further\n       processed. */\n    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, \n                        pcb->rcv_nxt + pcb->rcv_wnd - 1)){//rcv_nxt <  seqno < rcv_nxt + rcv_wnd - 1,������ڽ��շ�Χ��\n      if (pcb->rcv_nxt == seqno) {\n        /* The incoming segment is the next in sequence. We check if\n           we have to trim the end of the segment and update rcv_nxt\n           and pass the data to the application. */\n        tcplen = TCP_TCPLEN(&inseg);//���㱨�Ķγ���\n\n        if (tcplen > pcb->rcv_wnd) {//������մ��ڴ�С��������β���ض�\n          LWIP_DEBUGF(TCP_INPUT_DEBUG, \n                      (\"tcp_receive: other end overran receive window\"\n                       \"seqno %\"U32_F\" len %\"U16_F\" right edge %\"U32_F\"\\n\",\n                       seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));\n          if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {\n            /* Must remove the FIN from the header as we're trimming \n             * that byte of sequence-space from the packet */\n            TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);\n          }\n          /* Adjust length of segment to fit in the window. */\n          inseg.len = pcb->rcv_wnd;\n          if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {\n            inseg.len -= 1;\n          }\n          pbuf_realloc(inseg.p, inseg.len);\n          tcplen = TCP_TCPLEN(&inseg);\n          LWIP_ASSERT(\"tcp_receive: segment not trimmed correctly to rcv_wnd\\n\",\n                      (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));\n        }\n#if TCP_QUEUE_OOSEQ\n        /* Received in-sequence data, adjust ooseq data if:\n           - FIN has been received or\n           - inseq overlaps with ooseq */\n        if (pcb->ooseq != NULL) {\n          if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {\n            LWIP_DEBUGF(TCP_INPUT_DEBUG, \n                        (\"tcp_receive: received in-order FIN, binning ooseq queue\\n\"));\n            /* Received in-order FIN means anything that was received\n             * out of order must now have been received in-order, so\n             * bin the ooseq queue */\n            while (pcb->ooseq != NULL) {\n              struct tcp_seg *old_ooseq = pcb->ooseq;\n              pcb->ooseq = pcb->ooseq->next;\n              tcp_seg_free(old_ooseq);\n            }\n          }\n          else {\n            next = pcb->ooseq;\n            /* Remove all segments on ooseq that are covered by inseg already.\n             * FIN is copied from ooseq to inseg if present. */\n            while (next &&\n                   TCP_SEQ_GEQ(seqno + tcplen,\n                               next->tcphdr->seqno + next->len)) {\n              /* inseg cannot have FIN here (already processed above) */\n              if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&\n                  (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {\n                TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);\n                tcplen = TCP_TCPLEN(&inseg);\n              }\n              prev = next;\n              next = next->next;\n              tcp_seg_free(prev);\n            }\n            /* Now trim right side of inseg if it overlaps with the first\n             * segment on ooseq */\n            if (next &&\n                TCP_SEQ_GT(seqno + tcplen,\n                           next->tcphdr->seqno)) {\n              /* inseg cannot have FIN here (already processed above) */\n              inseg.len = (u16_t)(next->tcphdr->seqno - seqno);\n              if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {\n                inseg.len -= 1;\n              }\n              pbuf_realloc(inseg.p, inseg.len);\n              tcplen = TCP_TCPLEN(&inseg);\n              LWIP_ASSERT(\"tcp_receive: segment not trimmed correctly to ooseq queue\\n\",\n                          (seqno + tcplen) == next->tcphdr->seqno);\n            }\n            pcb->ooseq = next;\n          }\n        }\n#endif /* TCP_QUEUE_OOSEQ */\n\n        pcb->rcv_nxt = seqno + tcplen;\n\n        /* Update the receiver's (our) window. */\n        LWIP_ASSERT(\"tcp_receive: tcplen > rcv_wnd\\n\", pcb->rcv_wnd >= tcplen);\n        pcb->rcv_wnd -= tcplen;\n\n        tcp_update_rcv_ann_wnd(pcb);\n\n        /* If there is data in the segment, we make preparations to\n           pass this up to the application. The ->recv_data variable\n           is used for holding the pbuf that goes to the\n           application. The code for reassembling out-of-sequence data\n           chains its data on this pbuf as well.\n\n           If the segment was a FIN, we set the TF_GOT_FIN flag that will\n           be used to indicate to the application that the remote side has\n           closed its end of the connection. */\n        if (inseg.p->tot_len > 0) {\n          recv_data = inseg.p;\n          /* Since this pbuf now is the responsibility of the\n             application, we delete our reference to it so that we won't\n             (mistakingly) deallocate it. */\n          inseg.p = NULL;\n        }\n        if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {\n          LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_receive: received FIN.\\n\"));\n          recv_flags |= TF_GOT_FIN;\n        }\n\n#if TCP_QUEUE_OOSEQ\n        /* We now check if we have segments on the ->ooseq queue that\n           are now in sequence. */\n        while (pcb->ooseq != NULL &&\n               pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {\n\n          cseg = pcb->ooseq;\n          seqno = pcb->ooseq->tcphdr->seqno;\n\n          pcb->rcv_nxt += TCP_TCPLEN(cseg);\n          LWIP_ASSERT(\"tcp_receive: ooseq tcplen > rcv_wnd\\n\",\n                      pcb->rcv_wnd >= TCP_TCPLEN(cseg));\n          pcb->rcv_wnd -= TCP_TCPLEN(cseg);\n\n          tcp_update_rcv_ann_wnd(pcb);\n\n          if (cseg->p->tot_len > 0) {\n            /* Chain this pbuf onto the pbuf that we will pass to\n               the application. */\n            if (recv_data) {\n              pbuf_cat(recv_data, cseg->p);\n            } else {\n              recv_data = cseg->p;\n            }\n            cseg->p = NULL;\n          }\n          if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {\n            LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_receive: dequeued FIN.\\n\"));\n            recv_flags |= TF_GOT_FIN;\n            if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */\n              pcb->state = CLOSE_WAIT;\n            } \n          }\n\n          pcb->ooseq = cseg->next;\n          tcp_seg_free(cseg);\n        }\n#endif /* TCP_QUEUE_OOSEQ */\n\n\n        /* Acknowledge the segment(s). */\n        tcp_ack(pcb);\n\n      } else {\n        /* We get here if the incoming segment is out-of-sequence. */\n        tcp_send_empty_ack(pcb);\n#if TCP_QUEUE_OOSEQ\n        /* We queue the segment on the ->ooseq queue. */\n        if (pcb->ooseq == NULL) {\n          pcb->ooseq = tcp_seg_copy(&inseg);\n        } else {\n          /* If the queue is not empty, we walk through the queue and\n             try to find a place where the sequence number of the\n             incoming segment is between the sequence numbers of the\n             previous and the next segment on the ->ooseq queue. That is\n             the place where we put the incoming segment. If needed, we\n             trim the second edges of the previous and the incoming\n             segment so that it will fit into the sequence.\n\n             If the incoming segment has the same sequence number as a\n             segment on the ->ooseq queue, we discard the segment that\n             contains less data. */\n\n          prev = NULL;\n          for(next = pcb->ooseq; next != NULL; next = next->next) {//��ooseqȡ�µ�M�����ĶΣ��ñ��Ķηǿգ�M++\n            if (seqno == next->tcphdr->seqno) {//�ñ��Ķ���ʼ���== Ҫ����ı��Ķα��\n              /* The sequence number of the incoming segment is the\n                 same as the sequence number of the segment on\n                 ->ooseq. We check the lengths to see which one to\n                 discard. */\n              if (inseg.len > next->len) {//Ҫ����ı��Ķα�Ÿ�\n                /* The incoming segment is larger than the old\n                   segment. We replace some segments with the new\n                   one. */\n                cseg = tcp_seg_copy(&inseg);//Ҫ����ı��Ķδ����M�����Ķ�\n                if (cseg != NULL) {\n                  if (prev != NULL) {\n                    prev->next = cseg;\n                  } else {\n                    pcb->ooseq = cseg;\n                  }\n                  tcp_oos_insert_segment(cseg, next);\n                }\n                break;\n              } else {\n                /* Either the lenghts are the same or the incoming\n                   segment was smaller than the old one; in either\n                   case, we ditch the incoming segment. */\n                break;\n              }\n            } else {\n              if (prev == NULL) {\n                if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {\n                  /* The sequence number of the incoming segment is lower\n                     than the sequence number of the first segment on the\n                     queue. We put the incoming segment first on the\n                     queue. */\n                  cseg = tcp_seg_copy(&inseg);\n                  if (cseg != NULL) {\n                    pcb->ooseq = cseg;\n                    tcp_oos_insert_segment(cseg, next);\n                  }\n                  break;\n                }\n              } else {\n                /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&\n                  TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/\n                if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {\n                  /* The sequence number of the incoming segment is in\n                     between the sequence numbers of the previous and\n                     the next segment on ->ooseq. We trim trim the previous\n                     segment, delete next segments that included in received segment\n                     and trim received, if needed. */\n                  cseg = tcp_seg_copy(&inseg);\n                  if (cseg != NULL) {\n                    if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {\n                      /* We need to trim the prev segment. */\n                      prev->len = (u16_t)(seqno - prev->tcphdr->seqno);\n                      pbuf_realloc(prev->p, prev->len);\n                    }\n                    prev->next = cseg;\n                    tcp_oos_insert_segment(cseg, next);\n                  }\n                  break;\n                }\n              }\n              /* If the \"next\" segment is the last segment on the\n                 ooseq queue, we add the incoming segment to the end\n                 of the list. */\n              if (next->next == NULL &&\n                  TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {\n                if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {\n                  /* segment \"next\" already contains all data */\n                  break;\n                }\n                next->next = tcp_seg_copy(&inseg);\n                if (next->next != NULL) {\n                  if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {\n                    /* We need to trim the last segment. */\n                    next->len = (u16_t)(seqno - next->tcphdr->seqno);\n                    pbuf_realloc(next->p, next->len);\n                  }\n                  /* check if the remote side overruns our receive window */\n                  if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) {\n                    LWIP_DEBUGF(TCP_INPUT_DEBUG, \n                                (\"tcp_receive: other end overran receive window\"\n                                 \"seqno %\"U32_F\" len %\"U16_F\" right edge %\"U32_F\"\\n\",\n                                 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));\n                    if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {\n                      /* Must remove the FIN from the header as we're trimming \n                       * that byte of sequence-space from the packet */\n                      TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);\n                    }\n                    /* Adjust length of segment to fit in the window. */\n                    next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;\n                    pbuf_realloc(next->next->p, next->next->len);\n                    tcplen = TCP_TCPLEN(next->next);\n                    LWIP_ASSERT(\"tcp_receive: segment not trimmed correctly to rcv_wnd\\n\",\n                                (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));\n                  }\n                }\n                break;\n              }\n            }\n            prev = next;\n          }\n        }\n#endif /* TCP_QUEUE_OOSEQ */\n\n      }\n    } else {\n      /* The incoming segment is not withing the window. */\n      tcp_send_empty_ack(pcb);\n    }\n  } else {\n    /* Segments with length 0 is taken care of here. Segments that\n       fall out of the window are ACKed. */\n    /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||\n      TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/\n    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){\n      tcp_ack_now(pcb);//��Դ�˷���һ������ȷ�ϱ���\n    }\n  }\n}\n\n/**\n * Parses the options contained in the incoming segment. \n *\n * Called from tcp_listen_input() and tcp_process().\n * Currently, only the MSS option is supported!\n *\n * @param pcb the tcp_pcb for which a segment arrived\n */\nstatic void\ntcp_parseopt(struct tcp_pcb *pcb)\n{\n  u16_t c, max_c;\n  u16_t mss;\n  u8_t *opts, opt;\n#if LWIP_TCP_TIMESTAMPS\n  u32_t tsval;\n#endif\n\n  opts = (u8_t *)tcphdr + TCP_HLEN;\n\n  /* Parse the TCP MSS option, if present. */\n  if(TCPH_HDRLEN(tcphdr) > 0x5) {\n    max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;\n    for (c = 0; c < max_c; ) {\n      opt = opts[c];\n      switch (opt) {\n      case 0x00:\n        /* End of options. */\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_parseopt: EOL\\n\"));\n        return;\n      case 0x01:\n        /* NOP option. */\n        ++c;\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_parseopt: NOP\\n\"));\n        break;\n      case 0x02:\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_parseopt: MSS\\n\"));\n        if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {\n          /* Bad length */\n          LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_parseopt: bad length\\n\"));\n          return;\n        }\n        /* An MSS option with the right option length. */\n        mss = (opts[c + 2] << 8) | opts[c + 3];\n        /* Limit the mss to the configured TCP_MSS and prevent division by zero */\n        pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;\n        /* Advance to next option */\n        c += 0x04;\n        break;\n#if LWIP_TCP_TIMESTAMPS\n      case 0x08:\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_parseopt: TS\\n\"));\n        if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {\n          /* Bad length */\n          LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_parseopt: bad length\\n\"));\n          return;\n        }\n        /* TCP timestamp option with valid length */\n        tsval = (opts[c+2]) | (opts[c+3] << 8) | \n          (opts[c+4] << 16) | (opts[c+5] << 24);\n        if (flags & TCP_SYN) {\n          pcb->ts_recent = ntohl(tsval);\n          pcb->flags |= TF_TIMESTAMP;\n        } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {\n          pcb->ts_recent = ntohl(tsval);\n        }\n        /* Advance to next option */\n        c += 0x0A;\n        break;\n#endif\n      default:\n        LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_parseopt: other\\n\"));\n        if (opts[c + 1] == 0) {\n          LWIP_DEBUGF(TCP_INPUT_DEBUG, (\"tcp_parseopt: bad length\\n\"));\n          /* If the length field is zero, the options are malformed\n             and we don't process them further. */\n          return;\n        }\n        /* All other options have a length field, so that we easily\n           can skip past them. */\n        c += opts[c + 1];\n      }\n    }\n  }\n}\n\n#endif /* LWIP_TCP */\n"
  },
  {
    "path": "app/lwip/core/tcp_out.c",
    "content": "/**\n * @file\n * Transmission Control Protocol, outgoing traffic\n *\n * The output functions of TCP.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/tcp_impl.h\"\n#include \"lwip/def.h\"\n#include \"lwip/mem.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/sys.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/inet_chksum.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/snmp.h\"\n#include \"netif/etharp.h\"\n\n#include <string.h>\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/* Define some copy-macros for checksum-on-copy so that the code looks\n   nicer by preventing too many ifdef's. */\n#if TCP_CHECKSUM_ON_COPY\n#define TCP_DATA_COPY(dst, src, len, seg) do { \\\n  tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \\\n                     len, &seg->chksum, &seg->chksum_swapped); \\\n  seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)\n#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped)  \\\n  tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);\n#else /* TCP_CHECKSUM_ON_COPY*/\n#define TCP_DATA_COPY(dst, src, len, seg)                     MEMCPY(dst, src, len)\n#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len)\n#endif /* TCP_CHECKSUM_ON_COPY*/\n\n/** Define this to 1 for an extra check that the output checksum is valid\n * (usefule when the checksum is generated by the application, not the stack) */\n#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK\n#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK   0\n#endif\n\n/* Forward declarations.*/\nstatic void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);\n\n/** Allocate a pbuf and create a tcphdr at p->payload, used for output\n * functions other than the default tcp_output -> tcp_output_segment\n * (e.g. tcp_send_empty_ack, etc.)\n *\n * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr)\n * @param optlen length of header-options\n * @param datalen length of tcp data to reserve in pbuf\n * @param seqno_be seqno in network byte order (big-endian)\n * @return pbuf with p->payload being the tcp_hdr\n */\nstatic struct pbuf *ICACHE_FLASH_ATTR\ntcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,\n                      u32_t seqno_be /* already in network byte order */)\n{\n  struct tcp_hdr *tcphdr;\n  struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM);\n  if (p != NULL) {\n    LWIP_ASSERT(\"check that first pbuf can hold struct tcp_hdr\",\n                 (p->len >= TCP_HLEN + optlen));\n    tcphdr = (struct tcp_hdr *)p->payload;\n    tcphdr->src = htons(pcb->local_port);\n    tcphdr->dest = htons(pcb->remote_port);\n    tcphdr->seqno = seqno_be;\n    tcphdr->ackno = htonl(pcb->rcv_nxt);\n    TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);\n    tcphdr->wnd = htons(pcb->rcv_ann_wnd);\n    tcphdr->chksum = 0;\n    tcphdr->urgp = 0;\n\n    /* If we're sending a packet, update the announced right window edge */\n    pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;\n  }\n  return p;\n}\n\n/**\n * Called by tcp_close() to send a segment including FIN flag but not data.\n *\n * @param pcb the tcp_pcb over which to send a segment\n * @return ERR_OK if sent, another err_t otherwise\n */\nerr_t\ntcp_send_fin(struct tcp_pcb *pcb)\n{\n  /* first, try to add the fin to the last unsent segment */\n  if (pcb->unsent != NULL) {\n    struct tcp_seg *last_unsent;\n    for (last_unsent = pcb->unsent; last_unsent->next != NULL;\n         last_unsent = last_unsent->next);\n\n    if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {\n      /* no SYN/FIN/RST flag in the header, we can add the FIN flag */\n      TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);\n      return ERR_OK;\n    }\n  }\n  /* no data, no length, flags, copy=1, no optdata */\n  return tcp_enqueue_flags(pcb, TCP_FIN);\n}\n\n/**\n * Create a TCP segment with prefilled header.\n *\n * Called by tcp_write and tcp_enqueue_flags.\n *\n * @param pcb Protocol control block for the TCP connection.\n * @param p pbuf that is used to hold the TCP header.\n * @param flags TCP flags for header.\n * @param seqno TCP sequence number of this packet\n * @param optflags options to include in TCP header\n * @return a new tcp_seg pointing to p, or NULL.\n * The TCP header is filled in except ackno and wnd.\n * p is freed on failure.\n */\nstatic struct tcp_seg *ICACHE_FLASH_ATTR\ntcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags)\n{\n  struct tcp_seg *seg;\n  u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);\n\n  if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, (\"tcp_create_segment: no memory.\\n\"));\n    pbuf_free(p);\n    return NULL;\n  }\n  seg->flags = optflags;\n  seg->next = NULL;\n  seg->p = p;\n  seg->len = p->tot_len - optlen;\n#if TCP_OVERSIZE_DBGCHECK\n  seg->oversize_left = 0;\n#endif /* TCP_OVERSIZE_DBGCHECK */\n#if TCP_CHECKSUM_ON_COPY\n  seg->chksum = 0;\n  seg->chksum_swapped = 0;\n  /* check optflags */\n  LWIP_ASSERT(\"invalid optflags passed: TF_SEG_DATA_CHECKSUMMED\",\n              (optflags & TF_SEG_DATA_CHECKSUMMED) == 0);\n#endif /* TCP_CHECKSUM_ON_COPY */\n\n  /* build TCP header */\n  if (pbuf_header(p, TCP_HLEN)) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, (\"tcp_create_segment: no room for TCP header in pbuf.\\n\"));\n    TCP_STATS_INC(tcp.err);\n    tcp_seg_free(seg);\n    return NULL;\n  }\n  seg->tcphdr = (struct tcp_hdr *)seg->p->payload;\n  seg->tcphdr->src = htons(pcb->local_port);\n  seg->tcphdr->dest = htons(pcb->remote_port);\n  seg->tcphdr->seqno = htonl(seqno);\n  /* ackno is set in tcp_output */\n  TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags);\n  /* wnd and chksum are set in tcp_output */\n  seg->tcphdr->urgp = 0;\n  return seg;\n} \n\n/**\n * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end.\n *\n * This function is like pbuf_alloc(layer, length, PBUF_RAM) except\n * there may be extra bytes available at the end.\n *\n * @param layer flag to define header size.\n * @param length size of the pbuf's payload.\n * @param max_length maximum usable size of payload+oversize.\n * @param oversize pointer to a u16_t that will receive the number of usable tail bytes.\n * @param pcb The TCP connection that willo enqueue the pbuf.\n * @param apiflags API flags given to tcp_write.\n * @param first_seg true when this pbuf will be used in the first enqueued segment.\n * @param \n */\n#if TCP_OVERSIZE\nstatic struct pbuf *ICACHE_FLASH_ATTR\ntcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length,\n                  u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags,\n                  u8_t first_seg)\n{\n  struct pbuf *p;\n  u16_t alloc = length;\n\n#if LWIP_NETIF_TX_SINGLE_PBUF\n  LWIP_UNUSED_ARG(max_length);\n  LWIP_UNUSED_ARG(pcb);\n  LWIP_UNUSED_ARG(apiflags);\n  LWIP_UNUSED_ARG(first_seg);\n  /* always create MSS-sized pbufs */\n  alloc = TCP_MSS;\n#else /* LWIP_NETIF_TX_SINGLE_PBUF */\n  if (length < max_length) {\n    /* Should we allocate an oversized pbuf, or just the minimum\n     * length required? If tcp_write is going to be called again\n     * before this segment is transmitted, we want the oversized\n     * buffer. If the segment will be transmitted immediately, we can\n     * save memory by allocating only length. We use a simple\n     * heuristic based on the following information:\n     *\n     * Did the user set TCP_WRITE_FLAG_MORE?\n     *\n     * Will the Nagle algorithm defer transmission of this segment?\n     */\n    if ((apiflags & TCP_WRITE_FLAG_MORE) ||\n        (!(pcb->flags & TF_NODELAY) &&\n         (!first_seg ||\n          pcb->unsent != NULL ||\n          pcb->unacked != NULL))) {\n      alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE));\n    }\n  }\n#endif /* LWIP_NETIF_TX_SINGLE_PBUF */\n  p = pbuf_alloc(layer, alloc, PBUF_RAM);\n  if (p == NULL) {\n    return NULL;\n  }\n  LWIP_ASSERT(\"need unchained pbuf\", p->next == NULL);\n  *oversize = p->len - length;\n  /* trim p->len to the currently used size */\n  p->len = p->tot_len = length;\n  return p;\n}\n#else /* TCP_OVERSIZE */\n#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)\n#endif /* TCP_OVERSIZE */\n\n#if TCP_CHECKSUM_ON_COPY\n/** Add a checksum of newly added data to the segment */\nstatic void ICACHE_FLASH_ATTR\ntcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum,\n                   u8_t *seg_chksum_swapped)\n{\n  u32_t helper;\n  /* add chksum to old chksum and fold to u16_t */\n  helper = chksum + *seg_chksum;\n  chksum = FOLD_U32T(helper);\n  if ((len & 1) != 0) {\n    *seg_chksum_swapped = 1 - *seg_chksum_swapped;\n    chksum = SWAP_BYTES_IN_WORD(chksum);\n  }\n  *seg_chksum = chksum;\n}\n#endif /* TCP_CHECKSUM_ON_COPY */\n\n/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen).\n *\n * @param pcb the tcp pcb to check for\n * @param len length of data to send (checked agains snd_buf)\n * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise\n */\nstatic err_t ICACHE_FLASH_ATTR\ntcp_write_checks(struct tcp_pcb *pcb, u16_t len)\n{\n  /* connection is in invalid state for data transmission? */\n  if ((pcb->state != ESTABLISHED) &&\n      (pcb->state != CLOSE_WAIT) &&\n      (pcb->state != SYN_SENT) &&\n      (pcb->state != SYN_RCVD)) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, (\"tcp_write() called in invalid state\\n\"));\n    return ERR_CONN;\n  } else if (len == 0) {\n    return ERR_OK;\n  }\n\n  /* fail on too much data */\n  if (len > pcb->snd_buf) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, (\"tcp_write: too much data (len=%\"U16_F\" > snd_buf=%\"U16_F\")\\n\",\n      len, pcb->snd_buf));\n    pcb->flags |= TF_NAGLEMEMERR;\n    return ERR_MEM;\n  }\n\n  LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"tcp_write: queuelen: %\"U16_F\"\\n\", (u16_t)pcb->snd_queuelen));\n\n  /* If total number of pbufs on the unsent/unacked queues exceeds the\n   * configured maximum, return an error */\n  /* check for configured max queuelen and possible overflow */\n  if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, (\"tcp_write: too long queue %\"U16_F\" (max %\"U16_F\")\\n\",\n      pcb->snd_queuelen, TCP_SND_QUEUELEN));\n    TCP_STATS_INC(tcp.memerr);\n    pcb->flags |= TF_NAGLEMEMERR;\n    return ERR_MEM;\n  }\n  if (pcb->snd_queuelen != 0) {\n    LWIP_ASSERT(\"tcp_write: pbufs on queue => at least one queue non-empty\",\n      pcb->unacked != NULL || pcb->unsent != NULL);\n  } else {\n    LWIP_ASSERT(\"tcp_write: no pbufs on queue => both queues empty\",\n      pcb->unacked == NULL && pcb->unsent == NULL);\n  }\n  return ERR_OK;\n}\n\n/**\n * Write data for sending (but does not send it immediately).\n *��������һ��������ݣ��ú�����һ�����Ķβ����ڿ��ƿ黺�������\n * It waits in the expectation of more data being sent soon (as\n * it can send them more efficiently by combining them together).\n * To prompt the system to send data now, call tcp_output() after\n * calling tcp_write().\n *\n * @param pcb Protocol control block for the TCP connection to enqueue data for.��Ӧ���ӿ��ƿ�\n * @param arg Pointer to the data to be enqueued for sending.���������ʼ��ַ\n * @param len Data length in bytes������ݳ���\n * @param apiflags combination of following flags :����Ƿ���п������Լ����Ķ��ײ��Ƿ������PSH��־\n * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack\n * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,\n * @return ERR_OK if enqueued, another err_t on error\n */\nerr_t\ntcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)\n{\n  struct pbuf *concat_p = NULL;\n  struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL;\n  u16_t pos = 0; /* position in 'arg' data */\n  u16_t queuelen;\n  u8_t optlen = 0;\n  u8_t optflags = 0;\n#if TCP_OVERSIZE\n  u16_t oversize = 0;\n  u16_t oversize_used = 0;\n#endif /* TCP_OVERSIZE */\n#if TCP_CHECKSUM_ON_COPY\n  u16_t concat_chksum = 0;\n  u8_t concat_chksum_swapped = 0;\n  u16_t concat_chksummed = 0;\n#endif /* TCP_CHECKSUM_ON_COPY */\n  err_t err;\n\n#if LWIP_NETIF_TX_SINGLE_PBUF\n  /* Always copy to try to create single pbufs for TX */\n  apiflags |= TCP_WRITE_FLAG_COPY;\n#endif /* LWIP_NETIF_TX_SINGLE_PBUF */\n\n  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, (\"tcp_write(pcb=%p, data=%p, len=%\"U16_F\", apiflags=%\"U16_F\")\\n\",\n    (void *)pcb, arg, len, (u16_t)apiflags));\n  LWIP_ERROR(\"tcp_write: arg == NULL (programmer violates API)\", \n             arg != NULL, return ERR_ARG;);\n\n  err = tcp_write_checks(pcb, len);\n  if (err != ERR_OK) {\n    return err;\n  }\n  queuelen = pcb->snd_queuelen;\n\n#if LWIP_TCP_TIMESTAMPS\n  if ((pcb->flags & TF_TIMESTAMP)) {\n    optflags = TF_SEG_OPTS_TS;\n    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);\n  }\n#endif /* LWIP_TCP_TIMESTAMPS */\n\n\n  /*\n   * TCP segmentation is done in three phases with increasing complexity:\n   *\n   * 1. Copy data directly into an oversized pbuf.\n   * 2. Chain a new pbuf to the end of pcb->unsent.\n   * 3. Create new segments.\n   *\n   * We may run out of memory at any point. In that case we must\n   * return ERR_MEM and not change anything in pcb. Therefore, all\n   * changes are recorded in local variables and committed at the end\n   * of the function. Some pcb fields are maintained in local copies:\n   *\n   * queuelen = pcb->snd_queuelen\n   * oversize = pcb->unsent_oversize\n   *\n   * These variables are set consistently by the phases:\n   *\n   * seg points to the last segment tampered with.\n   *\n   * pos records progress as data is segmented.\n   */\n\n  /* Find the tail of the unsent queue. */\n  if (pcb->unsent != NULL) {\n    u16_t space;\n    u16_t unsent_optlen;\n\n    /* @todo: this could be sped up by keeping last_unsent in the pcb */\n    for (last_unsent = pcb->unsent; last_unsent->next != NULL;\n         last_unsent = last_unsent->next);\n\n    /* Usable space at the end of the last unsent segment */\n    unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);\n    space = pcb->mss - (last_unsent->len + unsent_optlen);\n\n    /*\n     * Phase 1: Copy data directly into an oversized pbuf.\n     *\n     * The number of bytes copied is recorded in the oversize_used\n     * variable. The actual copying is done at the bottom of the\n     * function.\n     */\n#if TCP_OVERSIZE\n#if TCP_OVERSIZE_DBGCHECK\n    /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */\n    LWIP_ASSERT(\"unsent_oversize mismatch (pcb vs. last_unsent)\",\n                pcb->unsent_oversize == last_unsent->oversize_left);\n#endif /* TCP_OVERSIZE_DBGCHECK */\n    oversize = pcb->unsent_oversize;\n    if (oversize > 0) {\n      LWIP_ASSERT(\"inconsistent oversize vs. space\", oversize_used <= space);\n      seg = last_unsent;\n      oversize_used = oversize < len ? oversize : len;\n      pos += oversize_used;\n      oversize -= oversize_used;\n      space -= oversize_used;\n    }\n    /* now we are either finished or oversize is zero */\n    LWIP_ASSERT(\"inconsistend oversize vs. len\", (oversize == 0) || (pos == len));\n#endif /* TCP_OVERSIZE */\n\n    /*\n     * Phase 2: Chain a new pbuf to the end of pcb->unsent.\n     *\n     * We don't extend segments containing SYN/FIN flags or options\n     * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at\n     * the end.\n     */\n    if ((pos < len) && (space > 0) && (last_unsent->len > 0)) {\n      u16_t seglen = space < len - pos ? space : len - pos;\n      seg = last_unsent;\n\n      /* Create a pbuf with a copy or reference to seglen bytes. We\n       * can use PBUF_RAW here since the data appears in the middle of\n       * a segment. A header will never be prepended. */\n      if (apiflags & TCP_WRITE_FLAG_COPY) {\n        /* Data is copied */\n        if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {\n          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,\n                      (\"tcp_write : could not allocate memory for pbuf copy size %\"U16_F\"\\n\",\n                       seglen));\n          goto memerr;\n        }\n#if TCP_OVERSIZE_DBGCHECK\n        last_unsent->oversize_left = oversize;\n#endif /* TCP_OVERSIZE_DBGCHECK */\n        TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);\n#if TCP_CHECKSUM_ON_COPY\n        concat_chksummed += seglen;\n#endif /* TCP_CHECKSUM_ON_COPY */\n      } else {\n        /* Data is not copied */\n        if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {\n          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,\n                      (\"tcp_write: could not allocate memory for zero-copy pbuf\\n\"));\n          goto memerr;\n        }\n#if TCP_CHECKSUM_ON_COPY\n        /* calculate the checksum of nocopy-data */\n        tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen,\n          &concat_chksum, &concat_chksum_swapped);\n        concat_chksummed += seglen;\n#endif /* TCP_CHECKSUM_ON_COPY */\n        /* reference the non-volatile payload data */\n        concat_p->payload = (u8_t*)arg + pos;\n      }\n\n      pos += seglen;\n      queuelen += pbuf_clen(concat_p);\n    }\n  } else {\n#if TCP_OVERSIZE\n    LWIP_ASSERT(\"unsent_oversize mismatch (pcb->unsent is NULL)\",\n                pcb->unsent_oversize == 0);\n#endif /* TCP_OVERSIZE */\n  }\n\n  /*\n   * Phase 3: Create new segments.\n   *\n   * The new segments are chained together in the local 'queue'\n   * variable, ready to be appended to pcb->unsent.\n   */\n  while (pos < len) {\n    struct pbuf *p;\n    u16_t left = len - pos;\n    u16_t max_len = pcb->mss - optlen;\n    u16_t seglen = left > max_len ? max_len : left;\n#if TCP_CHECKSUM_ON_COPY\n    u16_t chksum = 0;\n    u8_t chksum_swapped = 0;\n#endif /* TCP_CHECKSUM_ON_COPY */\n\n    if (apiflags & TCP_WRITE_FLAG_COPY) {\n      /* If copy is set, memory should be allocated and data copied\n       * into pbuf */\n      if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {\n        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, (\"tcp_write : could not allocate memory for pbuf copy size %\"U16_F\"\\n\", seglen));\n        goto memerr;\n      }\n      LWIP_ASSERT(\"tcp_write: check that first pbuf can hold the complete seglen\",\n                  (p->len >= seglen));\n      TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped);\n    } else {\n      /* Copy is not set: First allocate a pbuf for holding the data.\n       * Since the referenced data is available at least until it is\n       * sent out on the link (as it has to be ACKed by the remote\n       * party) we can safely use PBUF_ROM instead of PBUF_REF here.\n       */\n      struct pbuf *p2;\n#if TCP_OVERSIZE\n      LWIP_ASSERT(\"oversize == 0\", oversize == 0);\n#endif /* TCP_OVERSIZE */\n      if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {\n        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, (\"tcp_write: could not allocate memory for zero-copy pbuf\\n\"));\n        goto memerr;\n      }\n#if TCP_CHECKSUM_ON_COPY\n      /* calculate the checksum of nocopy-data */\n      chksum = ~inet_chksum((u8_t*)arg + pos, seglen);\n#endif /* TCP_CHECKSUM_ON_COPY */\n      /* reference the non-volatile payload data */\n      p2->payload = (u8_t*)arg + pos;\n\n      /* Second, allocate a pbuf for the headers. */\n      if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {\n        /* If allocation fails, we have to deallocate the data pbuf as\n         * well. */\n        pbuf_free(p2);\n        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, (\"tcp_write: could not allocate memory for header pbuf\\n\"));\n        goto memerr;\n      }\n      /* Concatenate the headers and data pbufs together. */\n      pbuf_cat(p/*header*/, p2/*data*/);\n    }\n\n    queuelen += pbuf_clen(p);\n\n    /* Now that there are more segments queued, we check again if the\n     * length of the queue exceeds the configured maximum or\n     * overflows. */\n    if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {\n      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, (\"tcp_write: queue too long %\"U16_F\" (%\"U16_F\")\\n\", queuelen, TCP_SND_QUEUELEN));\n      pbuf_free(p);\n      goto memerr;\n    }\n\n    if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {\n      goto memerr;\n    }\n#if TCP_OVERSIZE_DBGCHECK\n    seg->oversize_left = oversize;\n#endif /* TCP_OVERSIZE_DBGCHECK */\n#if TCP_CHECKSUM_ON_COPY\n    seg->chksum = chksum;\n    seg->chksum_swapped = chksum_swapped;\n    seg->flags |= TF_SEG_DATA_CHECKSUMMED;\n#endif /* TCP_CHECKSUM_ON_COPY */\n\n    /* first segment of to-be-queued data? */\n    if (queue == NULL) {\n      queue = seg;\n    } else {\n      /* Attach the segment to the end of the queued segments */\n      LWIP_ASSERT(\"prev_seg != NULL\", prev_seg != NULL);\n      prev_seg->next = seg;\n    }\n    /* remember last segment of to-be-queued data for next iteration */\n    prev_seg = seg;\n\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, (\"tcp_write: queueing %\"U32_F\":%\"U32_F\"\\n\",\n      ntohl(seg->tcphdr->seqno),\n      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));\n\n    pos += seglen;\n  }\n\n  /*\n   * All three segmentation phases were successful. We can commit the\n   * transaction.\n   */\n\n  /*\n   * Phase 1: If data has been added to the preallocated tail of\n   * last_unsent, we update the length fields of the pbuf chain.\n   */\n#if TCP_OVERSIZE\n  if (oversize_used > 0) {\n    struct pbuf *p;\n    /* Bump tot_len of whole chain, len of tail */\n    for (p = last_unsent->p; p; p = p->next) {\n      p->tot_len += oversize_used;\n      if (p->next == NULL) {\n        TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent);\n        p->len += oversize_used;\n      }\n    }\n    last_unsent->len += oversize_used;\n#if TCP_OVERSIZE_DBGCHECK\n    last_unsent->oversize_left -= oversize_used;\n#endif /* TCP_OVERSIZE_DBGCHECK */\n  }\n  pcb->unsent_oversize = oversize;\n#endif /* TCP_OVERSIZE */\n\n  /*\n   * Phase 2: concat_p can be concatenated onto last_unsent->p\n   */\n  if (concat_p != NULL) {\n    LWIP_ASSERT(\"tcp_write: cannot concatenate when pcb->unsent is empty\",\n      (last_unsent != NULL));\n    pbuf_cat(last_unsent->p, concat_p);\n    last_unsent->len += concat_p->tot_len;\n#if TCP_CHECKSUM_ON_COPY\n    if (concat_chksummed) {\n      tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,\n        &last_unsent->chksum_swapped);\n      last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;\n    }\n#endif /* TCP_CHECKSUM_ON_COPY */\n  }\n\n  /*\n   * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that\n   * is harmless\n   */\n  if (last_unsent == NULL) {\n    pcb->unsent = queue;\n  } else {\n    last_unsent->next = queue;\n  }\n\n  /*\n   * Finally update the pcb state.\n   */\n  pcb->snd_lbb += len;\n  pcb->snd_buf -= len;\n  pcb->snd_queuelen = queuelen;\n\n  LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"tcp_write: %\"S16_F\" (after enqueued)\\n\",\n    pcb->snd_queuelen));\n  if (pcb->snd_queuelen != 0) {\n    LWIP_ASSERT(\"tcp_write: valid queue length\",\n                pcb->unacked != NULL || pcb->unsent != NULL);\n  }\n\n  /* Set the PSH flag in the last segment that we enqueued. */\n  if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {\n    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);\n  }\n\n  return ERR_OK;\nmemerr:\n  pcb->flags |= TF_NAGLEMEMERR;\n  TCP_STATS_INC(tcp.memerr);\n\n  if (concat_p != NULL) {\n    pbuf_free(concat_p);\n  }\n  if (queue != NULL) {\n    tcp_segs_free(queue);\n  }\n  if (pcb->snd_queuelen != 0) {\n    LWIP_ASSERT(\"tcp_write: valid queue length\", pcb->unacked != NULL ||\n      pcb->unsent != NULL);\n  }\n  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, (\"tcp_write: %\"S16_F\" (with mem err)\\n\", pcb->snd_queuelen));\n  return ERR_MEM;\n}\n\n/**\n * Enqueue TCP options for transmission.\n *\n * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl().\n *\n * @param pcb Protocol control block for the TCP connection.\n * @param flags TCP header flags to set in the outgoing segment.\n * @param optdata pointer to TCP options, or NULL.\n * @param optlen length of TCP options in bytes.\n */\nerr_t\ntcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)\n{\n  struct pbuf *p;\n  struct tcp_seg *seg;\n  u8_t optflags = 0;\n  u8_t optlen = 0;\n\n  LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"tcp_enqueue_flags: queuelen: %\"U16_F\"\\n\", (u16_t)pcb->snd_queuelen));\n\n  LWIP_ASSERT(\"tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)\",\n              (flags & (TCP_SYN | TCP_FIN)) != 0);\n\n  /* check for configured max queuelen and possible overflow */\n  if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, (\"tcp_enqueue_flags: too long queue %\"U16_F\" (max %\"U16_F\")\\n\",\n                                       pcb->snd_queuelen, TCP_SND_QUEUELEN));\n    TCP_STATS_INC(tcp.memerr);\n    pcb->flags |= TF_NAGLEMEMERR;\n    return ERR_MEM;\n  }\n\n  if (flags & TCP_SYN) {\n    optflags = TF_SEG_OPTS_MSS;\n  }\n#if LWIP_TCP_TIMESTAMPS\n  if ((pcb->flags & TF_TIMESTAMP)) {\n    optflags |= TF_SEG_OPTS_TS;\n  }\n#endif /* LWIP_TCP_TIMESTAMPS */\n  optlen = LWIP_TCP_OPT_LENGTH(optflags);\n\n  /* tcp_enqueue_flags is always called with either SYN or FIN in flags.\n   * We need one available snd_buf byte to do that.\n   * This means we can't send FIN while snd_buf==0. A better fix would be to\n   * not include SYN and FIN sequence numbers in the snd_buf count. */\n  if (pcb->snd_buf == 0) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, (\"tcp_enqueue_flags: no send buffer available\\n\"));\n    TCP_STATS_INC(tcp.memerr);\n    return ERR_MEM;\n  }\n\n  /* Allocate pbuf with room for TCP header + options */\n  if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {\n    pcb->flags |= TF_NAGLEMEMERR;\n    TCP_STATS_INC(tcp.memerr);\n    return ERR_MEM;\n  }\n  LWIP_ASSERT(\"tcp_enqueue_flags: check that first pbuf can hold optlen\",\n              (p->len >= optlen));\n\n  /* Allocate memory for tcp_seg, and fill in fields. */\n  if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {\n    pcb->flags |= TF_NAGLEMEMERR;\n    TCP_STATS_INC(tcp.memerr);\n    return ERR_MEM;\n  }\n  LWIP_ASSERT(\"seg->tcphdr not aligned\", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);\n  LWIP_ASSERT(\"tcp_enqueue_flags: invalid segment length\", seg->len == 0);\n\n  LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,\n              (\"tcp_enqueue_flags: queueing %\"U32_F\":%\"U32_F\" (0x%\"X16_F\")\\n\",\n               ntohl(seg->tcphdr->seqno),\n               ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),\n               (u16_t)flags));\n\n  /* Now append seg to pcb->unsent queue */\n  if (pcb->unsent == NULL) {\n    pcb->unsent = seg;\n  } else {\n    struct tcp_seg *useg;\n    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);\n    useg->next = seg;\n  }\n#if TCP_OVERSIZE\n  /* The new unsent tail has no space */\n  pcb->unsent_oversize = 0;\n#endif /* TCP_OVERSIZE */\n\n  /* SYN and FIN bump the sequence number */\n  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {\n    pcb->snd_lbb++;\n    /* optlen does not influence snd_buf */\n    pcb->snd_buf--;\n  }\n  if (flags & TCP_FIN) {\n    pcb->flags |= TF_FIN;\n  }\n\n  /* update number of segments on the queues */\n  pcb->snd_queuelen += pbuf_clen(seg->p);\n  LWIP_DEBUGF(TCP_QLEN_DEBUG, (\"tcp_enqueue_flags: %\"S16_F\" (after enqueued)\\n\", pcb->snd_queuelen));\n  if (pcb->snd_queuelen != 0) {\n    LWIP_ASSERT(\"tcp_enqueue_flags: invalid queue length\",\n      pcb->unacked != NULL || pcb->unsent != NULL);\n  }\n\n  return ERR_OK;\n}\n \n\n#if LWIP_TCP_TIMESTAMPS\n/* Build a timestamp option (12 bytes long) at the specified options pointer)\n *\n * @param pcb tcp_pcb\n * @param opts option pointer where to store the timestamp option\n */\nstatic void ICACHE_FLASH_ATTR\ntcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)\n{\n  /* Pad with two NOP options to make everything nicely aligned */\n  opts[0] = PP_HTONL(0x0101080A);\n  opts[1] = htonl(sys_now());\n  opts[2] = htonl(pcb->ts_recent);\n}\n#endif\n\n/** Send an ACK without data.\n *\n * @param pcb Protocol control block for the TCP connection to send the ACK\n */\nerr_t\ntcp_send_empty_ack(struct tcp_pcb *pcb)\n{\n  struct pbuf *p;\n  struct tcp_hdr *tcphdr;\n  u8_t optlen = 0;\n\n#if LWIP_TCP_TIMESTAMPS\n  if (pcb->flags & TF_TIMESTAMP) {\n    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);\n  }\n#endif\n\n  p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));\n  if (p == NULL) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, (\"tcp_output: (ACK) could not allocate pbuf\\n\"));\n    return ERR_BUF;\n  }\n  tcphdr = (struct tcp_hdr *)p->payload;\n  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, \n              (\"tcp_output: sending ACK for %\"U32_F\"\\n\", pcb->rcv_nxt));\n  /* remove ACK flags from the PCB, as we send an empty ACK now */\n  pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\n\n  /* NB. MSS option is only sent on SYNs, so ignore it here */\n#if LWIP_TCP_TIMESTAMPS\n  pcb->ts_lastacksent = pcb->rcv_nxt;\n\n  if (pcb->flags & TF_TIMESTAMP) {\n    tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));\n  }\n#endif \n\n#if CHECKSUM_GEN_TCP\n  tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),\n        IP_PROTO_TCP, p->tot_len);\n#endif\n#if LWIP_NETIF_HWADDRHINT\n  ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\n      IP_PROTO_TCP, &(pcb->addr_hint));\n#else /* LWIP_NETIF_HWADDRHINT*/\n  ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\n      IP_PROTO_TCP);\n#endif /* LWIP_NETIF_HWADDRHINT*/\n  pbuf_free(p);\n\n  return ERR_OK;\n}\n\n/**\n * Find out what we can send and send it\n *���Ϳ��ƿ黺����еı��Ķ�\n * @param pcb Protocol control block for the TCP connection to send data\n * @return ERR_OK if data has been sent or nothing to send\n *         another err_t on error\n */\nerr_t ICACHE_FLASH_ATTR\ntcp_output(struct tcp_pcb *pcb)\n{\n  struct tcp_seg *seg, *useg;\n  u32_t wnd, snd_nxt;\n#if TCP_CWND_DEBUG\n  s16_t i = 0;\n#endif /* TCP_CWND_DEBUG */\n  /* First, check if we are invoked by the TCP input processing\n     code. If so, we do not output anything. Instead, we rely on the\n     input processing code to call us when input processing is done\n     with. �����ƿ鵱ǰ������ݱ����?ֱ�ӷ���*/\n  if (tcp_input_pcb == pcb) {\n    return ERR_OK;\n  }\n\n  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);//�ӷ��ʹ��ں������ȡС�ߵõ���Ч���ʹ���\n\n  seg = pcb->unsent;\n\n  /* If the TF_ACK_NOW flag is set and no data will be sent (either\n   * because the ->unsent queue is empty or because the window does\n   * not allow it), construct an empty ACK segment and send it.\n   *\n   * If data is to be sent, we will just piggyback the ACK (see below).\n   */\n  if (pcb->flags & TF_ACK_NOW &&\n     (seg == NULL ||\n      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {\n     return tcp_send_empty_ack(pcb);//����ֻ��ACK�ı��Ķ�\n  }\n\n  /* useg should point to last segment on unacked queue */\n  useg = pcb->unacked;\n  if (useg != NULL) {\n    for (; useg->next != NULL; useg = useg->next);//�õ�β��\n  }\n\n#if TCP_OUTPUT_DEBUG\n  if (seg == NULL) {\n    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, (\"tcp_output: nothing to send (%p)\\n\",\n                                   (void*)pcb->unsent));\n  }\n#endif /* TCP_OUTPUT_DEBUG */\n#if TCP_CWND_DEBUG\n  if (seg == NULL) {\n    LWIP_DEBUGF(TCP_CWND_DEBUG, (\"tcp_output: snd_wnd %\"U16_F\n                                 \", cwnd %\"U16_F\", wnd %\"U32_F\n                                 \", seg == NULL, ack %\"U32_F\"\\n\",\n                                 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));\n  } else {\n    LWIP_DEBUGF(TCP_CWND_DEBUG, \n                (\"tcp_output: snd_wnd %\"U16_F\", cwnd %\"U16_F\", wnd %\"U32_F\n                 \", effwnd %\"U32_F\", seq %\"U32_F\", ack %\"U32_F\"\\n\",\n                 pcb->snd_wnd, pcb->cwnd, wnd,\n                 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,\n                 ntohl(seg->tcphdr->seqno), pcb->lastack));\n  }\n#endif /* TCP_CWND_DEBUG */\n  /* data available and window allows it to be sent? \n    *��ǰ��Ч�������?�ķ��ͣ�ѭ�����ͱ��ģ�ֱ�������*/\n  while (seg != NULL &&\n         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {\n    LWIP_ASSERT(\"RST not expected here!\", \n                (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);\n    /* Stop sending if the nagle algorithm would prevent it\n     * Don't stop:\n     * - if tcp_write had a memory error before (prevent delayed ACK timeout) or\n     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -\n     *   either seg->next != NULL or pcb->unacked == NULL;\n     *   RST is no sent using tcp_write/tcp_output.\n     */\n    if((tcp_do_output_nagle(pcb) == 0) &&\n      ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){\n      break;\n    }\n#if TCP_CWND_DEBUG\n    LWIP_DEBUGF(TCP_CWND_DEBUG, (\"tcp_output: snd_wnd %\"U16_F\", cwnd %\"U16_F\", wnd %\"U32_F\", effwnd %\"U32_F\", seq %\"U32_F\", ack %\"U32_F\", i %\"S16_F\"\\n\",\n                            pcb->snd_wnd, pcb->cwnd, wnd,\n                            ntohl(seg->tcphdr->seqno) + seg->len -\n                            pcb->lastack,\n                            ntohl(seg->tcphdr->seqno), pcb->lastack, i));\n    ++i;\n#endif /* TCP_CWND_DEBUG */\n\n    pcb->unsent = seg->next;\n\n    if (pcb->state != SYN_SENT) {\n      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);//��д�ײ�ACK��־\n      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);//����־λ\n    }\n\n    tcp_output_segment(seg, pcb);//���ú����ͱ��Ķ�\n    \n    snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);//����snd_nxt\n    if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {\n      pcb->snd_nxt = snd_nxt;//����Ҫ���͵���ݱ��\n    }\n    /* put segment on unacknowledged list if length > 0\n    */\n    if (TCP_TCPLEN(seg) > 0) {\n      seg->next = NULL;\n      /* unacked list is empty? ֱ�ӹҽ�*/\n      if (pcb->unacked == NULL) {\n        pcb->unacked = seg;\n        useg = seg;\n      /* unacked list is not empty?����ǰ���İ�˳����֯�ڶ����� */\n      } else {\n        /* In the case of fast retransmit, the packet should not go to the tail\n         * of the unacked queue, but rather somewhere before it. We need to check for\n         * this case. -STJ Jul 27, 2004 */\t//���ǰ���ĵ����кŵ��ڶ���β���������кţ�\n         \t\t\t\t\t\t\t//�Ӷ����ײ���ʼ\n\t\tif (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {\n          /* add segment to before tail of unacked list, keeping the list sorted */\n          struct tcp_seg **cur_seg = &(pcb->unacked);\n          while (*cur_seg &&\n            TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {\n              cur_seg = &((*cur_seg)->next );\n          }\n          seg->next = (*cur_seg);\n          (*cur_seg) = seg;\n        } else {//���������ߣ������δȷ�϶���ĩβ\n          /* add segment to tail of unacked list */\n          useg->next = seg;\n          useg = useg->next;\n        }\n      }\n    /* do not queue empty segments on the unacked list */\n    } else {//���Ķγ���Ϊ0��ֱ��ɾ�������ش�\n\t  tcp_seg_free(seg);\n    }\n    seg = pcb->unsent;//������һ�����Ķ�\n  }\n#if TCP_OVERSIZE\n  if (pcb->unsent == NULL) {\n    /* last unsent has been removed, reset unsent_oversize */\n    pcb->unsent_oversize = 0;\n  }\n#endif /* TCP_OVERSIZE */\n\n//���ʹ��������±��Ĳ��ܷ��ͣ��������㴰��̽�⡣\n  if (seg != NULL && pcb->persist_backoff == 0 && \n      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {\n    /* prepare for persist timer */\n    pcb->persist_cnt = 0;\n    pcb->persist_backoff = 1;\n  }\n\n  pcb->flags &= ~TF_NAGLEMEMERR;//���ڴ�����־\n  return ERR_OK;\n}\n\n/**\n * Called by tcp_output() to actually send a TCP segment over IP.\n *\n * @param seg the tcp_seg to send\n * @param pcb the tcp_pcb for the TCP connection used to send the segment\n */\n\nstatic void\ntcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)\n{\n  u16_t len;\n  struct netif *netif;\n  u32_t *opts;\n  /** @bug Exclude retransmitted segments from this count. */\n  snmp_inc_tcpoutsegs();\n\n  /* The TCP header has already been constructed, but the ackno and\n   wnd fields remain. */\n  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);\n\n  /* advertise our receive window size in this TCP segment */\n  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);\n\n  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;\n\n  /* Add any requested options.  NB MSS option is only set on SYN\n     packets, so ignore it here */\n  LWIP_ASSERT(\"seg->tcphdr not aligned\", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);\n  opts = (u32_t *)(void *)(seg->tcphdr + 1);\n  if (seg->flags & TF_SEG_OPTS_MSS) {\n    TCP_BUILD_MSS_OPTION(*opts);\n    opts += 1;\n  }\n#if LWIP_TCP_TIMESTAMPS\n  pcb->ts_lastacksent = pcb->rcv_nxt;\n\n  if (seg->flags & TF_SEG_OPTS_TS) {\n    tcp_build_timestamp_option(pcb, opts);\n    opts += 3;\n  }\n#endif\n\n  /* Set retransmission timer running if it is not currently enabled \n     This must be set before checking the route. modify by ives at 2014.4.24*/\n  if (pcb->rtime == -1) {\n    pcb->rtime = 0;\n  }\n\n  /* If we don't have a local IP address, we get one by\n     calling ip_route(). */\n  if (ip_addr_isany(&(pcb->local_ip))) {\n    netif = ip_route(&(pcb->remote_ip));\n    if (netif == NULL) {\n      return;\n    }\n    ip_addr_copy(pcb->local_ip, netif->ip_addr);\n  }\n\n  if (pcb->rttest == 0) {\n    pcb->rttest = tcp_ticks;\n    pcb->rtseq = ntohl(seg->tcphdr->seqno);\n\n    LWIP_DEBUGF(TCP_RTO_DEBUG, (\"tcp_output_segment: rtseq %\"U32_F\"\\n\", pcb->rtseq));\n  }\n  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, (\"tcp_output_segment: %\"U32_F\":%\"U32_F\"\\n\",\n          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +\n          seg->len));\n\n  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);\n\n  seg->p->len -= len;\n  seg->p->tot_len -= len;\n\n  seg->p->payload = seg->tcphdr;\n\n  seg->tcphdr->chksum = 0;\n#if CHECKSUM_GEN_TCP\n#if TCP_CHECKSUM_ON_COPY\n  {\n    u32_t acc;\n#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK\n    u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),\n           &(pcb->remote_ip),\n           IP_PROTO_TCP, seg->p->tot_len);\n#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */\n    if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {\n      LWIP_ASSERT(\"data included but not checksummed\",\n        seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));\n    }\n\n    /* rebuild TCP header checksum (TCP header changes for retransmissions!) */\n    acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),\n             &(pcb->remote_ip),\n             IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);\n    /* add payload checksum */\n    if (seg->chksum_swapped) {\n      seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);\n      seg->chksum_swapped = 0;\n    }\n    acc += (u16_t)~(seg->chksum);\n    seg->tcphdr->chksum = FOLD_U32T(acc);\n#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK\n    if (chksum_slow != seg->tcphdr->chksum) {\n      LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,\n                  (\"tcp_output_segment: calculated checksum is %\"X16_F\" instead of %\"X16_F\"\\n\",\n                  seg->tcphdr->chksum, chksum_slow));\n      seg->tcphdr->chksum = chksum_slow;\n    }\n#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */\n  }\n#else /* TCP_CHECKSUM_ON_COPY */\n  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),\n         &(pcb->remote_ip),\n         IP_PROTO_TCP, seg->p->tot_len);\n#endif /* TCP_CHECKSUM_ON_COPY */\n#endif /* CHECKSUM_GEN_TCP */\n  TCP_STATS_INC(tcp.xmit);\n\n#if LWIP_NETIF_HWADDRHINT\n  ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\n      IP_PROTO_TCP, &(pcb->addr_hint));\n#else /* LWIP_NETIF_HWADDRHINT*/\n  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\n      IP_PROTO_TCP);\n#endif /* LWIP_NETIF_HWADDRHINT*/\n}\n\n/**\n * Send a TCP RESET packet (empty segment with RST flag set) either to\n * abort a connection or to show that there is no matching local connection\n * for a received segment.\n *\n * Called by tcp_abort() (to abort a local connection), tcp_input() (if no\n * matching local pcb was found), tcp_listen_input() (if incoming segment\n * has ACK flag set) and tcp_process() (received segment in the wrong state)\n *\n * Since a RST segment is in most cases not sent for an active connection,\n * tcp_rst() has a number of arguments that are taken from a tcp_pcb for\n * most other segment output functions.\n *\n * @param seqno the sequence number to use for the outgoing segment\n * @param ackno the acknowledge number to use for the outgoing segment\n * @param local_ip the local IP address to send the segment from\n * @param remote_ip the remote IP address to send the segment to\n * @param local_port the local TCP port to send the segment from\n * @param remote_port the remote TCP port to send the segment to\n */\nvoid\ntcp_rst(u32_t seqno, u32_t ackno,\n  ip_addr_t *local_ip, ip_addr_t *remote_ip,\n  u16_t local_port, u16_t remote_port)\n{\n  struct pbuf *p;\n  struct tcp_hdr *tcphdr;\n  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\n  if (p == NULL) {\n      LWIP_DEBUGF(TCP_DEBUG, (\"tcp_rst: could not allocate memory for pbuf\\n\"));\n      return;\n  }\n  LWIP_ASSERT(\"check that first pbuf can hold struct tcp_hdr\",\n              (p->len >= sizeof(struct tcp_hdr)));\n\n  tcphdr = (struct tcp_hdr *)p->payload;\n  tcphdr->src = htons(local_port);\n  tcphdr->dest = htons(remote_port);\n  tcphdr->seqno = htonl(seqno);\n  tcphdr->ackno = htonl(ackno);\n  TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);\n  tcphdr->wnd = PP_HTONS(TCP_WND);\n  tcphdr->chksum = 0;\n  tcphdr->urgp = 0;\n\n#if CHECKSUM_GEN_TCP\n  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,\n              IP_PROTO_TCP, p->tot_len);\n#endif\n  TCP_STATS_INC(tcp.xmit);\n  snmp_inc_tcpoutrsts();\n   /* Send output with hardcoded TTL since we have no access to the pcb */\n  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);\n  pbuf_free(p);\n  LWIP_DEBUGF(TCP_RST_DEBUG, (\"tcp_rst: seqno %\"U32_F\" ackno %\"U32_F\".\\n\", seqno, ackno));\n}\n\n/**\n * Requeue all unacked segments for retransmission\n *\n * Called by tcp_slowtmr() for slow retransmission.\n *\n * @param pcb the tcp_pcb for which to re-enqueue all unacked segments\n */\nvoid\ntcp_rexmit_rto(struct tcp_pcb *pcb)\n{\n  struct tcp_seg *seg;\n  struct tcp_seg *t0_head = NULL, *t0_tail = NULL; /* keep in unacked */\n  struct tcp_seg *t1_head = NULL, *t1_tail = NULL; /* link to unsent */\n  bool t0_1st = true, t1_1st = true;\n\n  if (pcb->unacked == NULL) {\n    return;\n  }\n\n#if 1 /* by Snake: resolve the bug of pbuf reuse */\n  seg = pcb->unacked;\n  while (seg != NULL) {\n\tif (seg->p->eb) {\n\t\tif (t0_1st) {\n\t\t\tt0_head = t0_tail = seg;\n\t\t\tt0_1st = false;\n\t\t} else {\n\t\t\tt0_tail->next = seg;\n\t\t\tt0_tail = seg;\n\t\t}\n\t\tseg = seg->next;\n\t\tt0_tail->next = NULL;\n\t} else {\n\t\tif (t1_1st) {\n\t\t\tt1_head = t1_tail = seg;\n\t\t\tt1_1st = false;\n\t\t} else {\n\t\t\tt1_tail->next = seg;\n\t\t\tt1_tail = seg;\n\t\t}\n\t\tseg = seg->next;\n\t\tt1_tail->next = NULL;\n\t}\n  }\n  if (t1_head && t1_tail) {\n\tt1_tail->next = pcb->unsent;\n\tpcb->unsent = t1_head;\n  }\n  pcb->unacked = t0_head;\n\n#else\n\n  /* Move all unacked segments to the head of the unsent queue */\n  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);\n  /* concatenate unsent queue after unacked queue */\n  seg->next = pcb->unsent;\n  /* unsent queue is the concatenated queue (of unacked, unsent) */\n  pcb->unsent = pcb->unacked;\n  /* unacked queue is now empty */\n  pcb->unacked = NULL;\n#endif\n\n  /* increment number of retransmissions */\n  ++pcb->nrtx;\n\n  /* Don't take any RTT measurements after retransmitting. */\n  pcb->rttest = 0;\n\n  /* Do the actual retransmission */\n  tcp_output(pcb);\n}\n\n/**\n * Requeue the first unacked segment for retransmission\n *\n * Called by tcp_receive() for fast retramsmit.\n *\n * @param pcb the tcp_pcb for which to retransmit the first unacked segment\n */\nvoid\ntcp_rexmit(struct tcp_pcb *pcb)\n{\n  struct tcp_seg *seg;\n  struct tcp_seg **cur_seg;\n\n  if (pcb->unacked == NULL) {\n    return;\n  }\n\n  /* Move the first unacked segment to the unsent queue */\n  /* Keep the unsent queue sorted. */\n  seg = pcb->unacked;\n  pcb->unacked = seg->next;\n\n  cur_seg = &(pcb->unsent);\n  while (*cur_seg &&\n    TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {\n      cur_seg = &((*cur_seg)->next );\n  }\n  seg->next = *cur_seg;\n  *cur_seg = seg;\n\n  ++pcb->nrtx;\n\n  /* Don't take any rtt measurements after retransmitting. */\n  pcb->rttest = 0;\n\n  /* Do the actual retransmission. */\n  snmp_inc_tcpretranssegs();\n  /* No need to call tcp_output: we are always called from tcp_input()\n     and thus tcp_output directly returns. */\n}\n\n\n/**\n * Handle retransmission after three dupacks received\n *\n * @param pcb the tcp_pcb for which to retransmit the first unacked segment\n */\nvoid \ntcp_rexmit_fast(struct tcp_pcb *pcb)\n{\n  if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {\n    /* This is fast retransmit. Retransmit the first unacked segment. */\n    LWIP_DEBUGF(TCP_FR_DEBUG, \n                (\"tcp_receive: dupacks %\"U16_F\" (%\"U32_F\n                 \"), fast retransmit %\"U32_F\"\\n\",\n                 (u16_t)pcb->dupacks, pcb->lastack,\n                 ntohl(pcb->unacked->tcphdr->seqno)));\n    tcp_rexmit(pcb);\n\n    /* Set ssthresh to half of the minimum of the current\n     * cwnd and the advertised window */\n    if (pcb->cwnd > pcb->snd_wnd) {\n      pcb->ssthresh = pcb->snd_wnd / 2;\n    } else {\n      pcb->ssthresh = pcb->cwnd / 2;\n    }\n    \n    /* The minimum value for ssthresh should be 2 MSS */\n    if (pcb->ssthresh < 2*pcb->mss) {\n      LWIP_DEBUGF(TCP_FR_DEBUG, \n                  (\"tcp_receive: The minimum value for ssthresh %\"U16_F\n                   \" should be min 2 mss %\"U16_F\"...\\n\",\n                   pcb->ssthresh, 2*pcb->mss));\n      pcb->ssthresh = 2*pcb->mss;\n    }\n    \n    pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;\n    pcb->flags |= TF_INFR;\n  } \n}\n\n\n/**\n * Send keepalive packets to keep a connection active although\n * no data is sent over it.\n *\n * Called by tcp_slowtmr()\n *\n * @param pcb the tcp_pcb for which to send a keepalive packet\n */\nvoid\ntcp_keepalive(struct tcp_pcb *pcb)\n{\n  struct pbuf *p;\n  struct tcp_hdr *tcphdr;\n\n  LWIP_DEBUGF(TCP_DEBUG, (\"tcp_keepalive: sending KEEPALIVE probe to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n                          ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),\n                          ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));\n\n  LWIP_DEBUGF(TCP_DEBUG, (\"tcp_keepalive: tcp_ticks %\"U32_F\"   pcb->tmr %\"U32_F\" pcb->keep_cnt_sent %\"U16_F\"\\n\", \n                          tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));\n   \n  p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));\n  if(p == NULL) {\n    LWIP_DEBUGF(TCP_DEBUG, \n                (\"tcp_keepalive: could not allocate memory for pbuf\\n\"));\n    return;\n  }\n  tcphdr = (struct tcp_hdr *)p->payload;\n\n#if CHECKSUM_GEN_TCP\n  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,\n                                      IP_PROTO_TCP, p->tot_len);\n#endif\n  TCP_STATS_INC(tcp.xmit);\n\n  /* Send output to IP */\n#if LWIP_NETIF_HWADDRHINT\n  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,\n    &(pcb->addr_hint));\n#else /* LWIP_NETIF_HWADDRHINT*/\n  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);\n#endif /* LWIP_NETIF_HWADDRHINT*/\n\n  pbuf_free(p);\n\n  LWIP_DEBUGF(TCP_DEBUG, (\"tcp_keepalive: seqno %\"U32_F\" ackno %\"U32_F\".\\n\",\n                          pcb->snd_nxt - 1, pcb->rcv_nxt));\n}\n\n\n/**\n * Send persist timer zero-window probes to keep a connection active\n * when a window update is lost.\n *\n * Called by tcp_slowtmr()\n *\n * @param pcb the tcp_pcb for which to send a zero-window probe packet\n */\nvoid\ntcp_zero_window_probe(struct tcp_pcb *pcb)\n{\n  struct pbuf *p;\n  struct tcp_hdr *tcphdr;\n  struct tcp_seg *seg;\n  u16_t  offset = 0;\n  u16_t len;\n  u8_t is_fin;\n\n  LWIP_DEBUGF(TCP_DEBUG, \n              (\"tcp_zero_window_probe: sending ZERO WINDOW probe to %\"\n               U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n               ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),\n               ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));\n\n  LWIP_DEBUGF(TCP_DEBUG, \n              (\"tcp_zero_window_probe: tcp_ticks %\"U32_F\n               \"   pcb->tmr %\"U32_F\" pcb->keep_cnt_sent %\"U16_F\"\\n\", \n               tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));\n\n  seg = pcb->unacked;\n\n  if(seg == NULL) {\n    seg = pcb->unsent;\n  } else {\n\t  struct ip_hdr *iphdr = NULL;\n\t  iphdr = (struct ip_hdr *)((char*)seg->p->payload + SIZEOF_ETH_HDR);\n\t  offset = IPH_HL(iphdr)*4;\n\t  offset += SIZEOF_ETH_HDR;\n  }\n  if(seg == NULL) {\n    return;\n  }\n\n  is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);\n  /* we want to send one seqno: either FIN or data (no options) */\n  len = is_fin ? 0 : 1;\n\n  p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);\n  if(p == NULL) {\n    LWIP_DEBUGF(TCP_DEBUG, (\"tcp_zero_window_probe: no memory for pbuf\\n\"));\n    return;\n  }\n  tcphdr = (struct tcp_hdr *)p->payload;\n\n  if (is_fin) {\n    /* FIN segment, no data */\n    TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);\n  } else {\n    /* Data segment, copy in one byte from the head of the unacked queue */\n    struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload;\n    char *d = ((char *)p->payload + TCP_HLEN);\n    if (pcb->unacked == NULL)\n    \tpbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);\n    else {\n    \tthdr = (struct tcp_hdr *)((char*)seg->p->payload + offset);\n    \tpbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4 + offset);\n    }\n  }\n\n#if CHECKSUM_GEN_TCP\n  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,\n                                      IP_PROTO_TCP, p->tot_len);\n#endif\n  TCP_STATS_INC(tcp.xmit);\n\n  /* Send output to IP */\n#if LWIP_NETIF_HWADDRHINT\n  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,\n    &(pcb->addr_hint));\n#else /* LWIP_NETIF_HWADDRHINT*/\n  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);\n#endif /* LWIP_NETIF_HWADDRHINT*/\n\n  pbuf_free(p);\n\n  LWIP_DEBUGF(TCP_DEBUG, (\"tcp_zero_window_probe: seqno %\"U32_F\n                          \" ackno %\"U32_F\".\\n\",\n                          pcb->snd_nxt - 1, pcb->rcv_nxt));\n}\n#endif /* LWIP_TCP */\n"
  },
  {
    "path": "app/lwip/core/timers.c",
    "content": "/**\n * @file\n * Stack-internal timers implementation.\n * This file includes timer callbacks for stack-internal timers as well as\n * functions to set up or stop timers and check for expired timers.\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *         Simon Goldschmidt\n *\n */\n\n#include \"lwip/opt.h\"\n\n#include \"lwip/timers.h\"\n#include \"lwip/tcp_impl.h\"\n\n#if LWIP_TIMERS\n\n#include \"lwip/def.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/tcpip.h\"\n\n#include \"lwip/ip_frag.h\"\n#include \"netif/etharp.h\"\n#include \"lwip/dhcp.h\"\n#include \"lwip/autoip.h\"\n#include \"lwip/igmp.h\"\n#include \"lwip/dns.h\"\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/** The one and only timeout list */\nstatic struct sys_timeo *next_timeout = NULL;\n#if NO_SYS\nstatic u32_t timeouts_last_time;\n#endif /* NO_SYS */\n\n#if LWIP_TCP\n/** global variable that shows if the tcp timer is currently scheduled or not */\nstatic int tcpip_tcp_timer_active;\n\n/**\n * Timer callback function that calls tcp_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\nstatic void ICACHE_FLASH_ATTR\ntcpip_tcp_timer(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n\n  /* call TCP timer handler */\n  tcp_tmr();\n  /* timer still needed? */\n  if (tcp_active_pcbs || tcp_tw_pcbs) {\n    /* restart timer */\n    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);\n  } else {\n    /* disable timer */\n    tcpip_tcp_timer_active = 0;\n  }\n}\n\n/**\n * Called from TCP_REG when registering a new PCB:\n * the reason is to have the TCP timer only running when\n * there are active (or time-wait) PCBs.\n */\nvoid\ntcp_timer_needed(void)\n{\n  /* timer is off but needed again? */\n  if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {\n    /* enable and start timer */\n    tcpip_tcp_timer_active = 1;\n    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);\n  }\n}\n\n/**\n * Timer callback function that calls tcp_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\n\nstatic void ICACHE_FLASH_ATTR\ntcp_timer_coarse(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"tcpip: tcp_tmr()\\n\"));\n  tcp_tmr();\n  sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL);\n}\n\n#endif /* LWIP_TCP */\n\n#if IP_REASSEMBLY\n/**\n * Timer callback function that calls ip_reass_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\nstatic void ICACHE_FLASH_ATTR\nip_reass_timer(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"tcpip: ip_reass_tmr()\\n\"));\n  ip_reass_tmr();\n  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);\n}\n#endif /* IP_REASSEMBLY */\n\n#if LWIP_ARP\n/**\n * Timer callback function that calls etharp_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\nstatic void ICACHE_FLASH_ATTR\narp_timer(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"tcpip: etharp_tmr()\\n\"));\n  etharp_tmr();\n  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);\n}\n#endif /* LWIP_ARP */\n\n#if LWIP_DHCP\n/**\n * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\nextern void dhcps_coarse_tmr(void);\nstatic void\ndhcp_timer_coarse(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"tcpip: dhcp_coarse_tmr()\\n\"));\n  dhcp_coarse_tmr();\n  dhcps_coarse_tmr();\n  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);\n}\n\n/**\n * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\nstatic void\ndhcp_timer_fine(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"tcpip: dhcp_fine_tmr()\\n\"));\n  dhcp_fine_tmr();\n  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);\n}\n#endif /* LWIP_DHCP */\n\n#if LWIP_AUTOIP\n/**\n * Timer callback function that calls autoip_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\nstatic void\nautoip_timer(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"tcpip: autoip_tmr()\\n\"));\n  autoip_tmr();\n  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);\n}\n#endif /* LWIP_AUTOIP */\n\n#if LWIP_IGMP\n/**\n * Timer callback function that calls igmp_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\nstatic void\nigmp_timer(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"tcpip: igmp_tmr()\\n\"));\n  igmp_tmr();\n  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);\n}\n#endif /* LWIP_IGMP */\n\n#if LWIP_DNS\n/**\n * Timer callback function that calls dns_tmr() and reschedules itself.\n *\n * @param arg unused argument\n */\nstatic void\ndns_timer(void *arg)\n{\n  LWIP_UNUSED_ARG(arg);\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"tcpip: dns_tmr()\\n\"));\n  dns_tmr();\n  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);\n}\n#endif /* LWIP_DNS */\n\n/** Initialize this module */\nvoid sys_timeouts_init(void)\n{\n#if IP_REASSEMBLY\n  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);\n#endif /* IP_REASSEMBLY */\n#if LWIP_ARP\n  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);\n#endif /* LWIP_ARP */\n#if LWIP_DHCP\n  DHCP_MAXRTX = 0;\n  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);\n  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);\n#endif /* LWIP_DHCP */\n#if LWIP_AUTOIP\n  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);\n#endif /* LWIP_AUTOIP */\n#if LWIP_IGMP\n  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);\n#endif /* LWIP_IGMP */\n#if LWIP_DNS\n  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);\n#endif /* LWIP_DNS */\n\n#if LWIP_TCP\n  sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);\n//  sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL);\n#endif\n\n#if NO_SYS\n  /* Initialise timestamp for sys_check_timeouts */\n  timeouts_last_time = NOW();\n#endif\n}\n\n/**\n * Create a one-shot timer (aka timeout). Timeouts are processed in the\n * following cases:\n * - while waiting for a message using sys_timeouts_mbox_fetch()\n * - by calling sys_check_timeouts() (NO_SYS==1 only)\n *\n * @param msecs time in milliseconds after that the timer should expire\n * @param handler callback function to call when msecs have elapsed\n * @param arg argument to pass to the callback function\n */\n#if LWIP_DEBUG_TIMERNAMES\nvoid\nsys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)\n#else /* LWIP_DEBUG_TIMERNAMES */\nvoid\nsys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)\n#endif /* LWIP_DEBUG_TIMERNAMES */\n{\n  struct sys_timeo *timeout, *t;\n\n  timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);\n  if (timeout == NULL) {\n    LWIP_ASSERT(\"sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty\", timeout != NULL);\n    return;\n  }\n  timeout->next = NULL;\n  timeout->h = handler;\n  timeout->arg = arg;\n  timeout->time = msecs;\n#if LWIP_DEBUG_TIMERNAMES\n  timeout->handler_name = handler_name;\n  LWIP_DEBUGF(TIMERS_DEBUG, (\"sys_timeout: %p msecs=%\"U32_F\" handler=%s arg=%p\\n\",\n    (void *)timeout, msecs, handler_name, (void *)arg));\n#endif /* LWIP_DEBUG_TIMERNAMES */\n\n  if (next_timeout == NULL) {\n    next_timeout = timeout;\n    return;\n  }\n\n  if (next_timeout->time > msecs) {\n    next_timeout->time -= msecs;\n    timeout->next = next_timeout;\n    next_timeout = timeout;\n  } else {\n    for(t = next_timeout; t != NULL; t = t->next) {\n      timeout->time -= t->time;\n      if (t->next == NULL || t->next->time > timeout->time) {\n        if (t->next != NULL) {\n          t->next->time -= timeout->time;\n        }\n        timeout->next = t->next;\n        t->next = timeout;\n        break;\n      }\n    }\n  }\n}\n\n/**\n * Go through timeout list (for this task only) and remove the first matching\n * entry, even though the timeout has not triggered yet.\n *\n * @note This function only works as expected if there is only one timeout\n * calling 'handler' in the list of timeouts.\n *\n * @param handler callback function that would be called by the timeout\n * @param arg callback argument that would be passed to handler\n*/\nvoid\nsys_untimeout(sys_timeout_handler handler, void *arg)\n{\n  struct sys_timeo *prev_t, *t;\n\n  if (next_timeout == NULL) {\n    return;\n  }\n\n  for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {\n    if ((t->h == handler) && (t->arg == arg)) {\n      /* We have a match */\n      /* Unlink from previous in list */\n      if (prev_t == NULL) {\n        next_timeout = t->next;\n      } else {\n        prev_t->next = t->next;\n      }\n      /* If not the last one, add time of this one back to next */\n      if (t->next != NULL) {\n        t->next->time += t->time;\n      }\n      memp_free(MEMP_SYS_TIMEOUT, t);\n      return;\n    }\n  }\n  return;\n}\n\n#if NO_SYS\nextern uint8 timer2_ms_flag;\n/** Handle timeouts for NO_SYS==1 (i.e. without using\n * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout\n * handler functions when timeouts expire.\n *\n * Must be called periodically from your main loop.\n */\nvoid\nsys_check_timeouts(void)\n{\n  struct sys_timeo *tmptimeout;\n  u32_t diff;\n  sys_timeout_handler handler;\n  void *arg;\n  int had_one;\n  u32_t now;\n\n  now = NOW();\n  if (next_timeout) {\n    /* this cares for wraparounds */\n\tif (timer2_ms_flag == 0) {\n\t\tdiff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>4)/1000);\n\t} else {\n\t\tdiff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>8)/1000);\n\t}\n    do\n    {\n      had_one = 0;\n      tmptimeout = next_timeout;\n      if (tmptimeout->time <= diff) {\n        /* timeout has expired */\n        had_one = 1;\n        timeouts_last_time = now;\n        diff -= tmptimeout->time;\n        next_timeout = tmptimeout->next;\n        handler = tmptimeout->h;\n        arg = tmptimeout->arg;\n#if LWIP_DEBUG_TIMERNAMES\n        if (handler != NULL) {\n          LWIP_DEBUGF(TIMERS_DEBUG, (\"sct calling h=%s arg=%p\\n\",\n            tmptimeout->handler_name, arg));\n        }\n#endif /* LWIP_DEBUG_TIMERNAMES */\n        memp_free(MEMP_SYS_TIMEOUT, tmptimeout);\n        if (handler != NULL) {\n          handler(arg);\n        }\n      }\n    /* repeat until all expired timers have been called */\n    }while(had_one);\n  }\n}\n\n/** Set back the timestamp of the last call to sys_check_timeouts()\n * This is necessary if sys_check_timeouts() hasn't been called for a long\n * time (e.g. while saving energy) to prevent all timer functions of that\n * period being called.\n */\nvoid\nsys_restart_timeouts(void)\n{\n  timeouts_last_time = NOW();\n}\n\n#else /* NO_SYS */\n\n/**\n * Wait (forever) for a message to arrive in an mbox.\n * While waiting, timeouts are processed.\n *\n * @param mbox the mbox to fetch the message from\n * @param msg the place to store the message\n */\nvoid\nsys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)\n{\n  u32_t time_needed;\n  struct sys_timeo *tmptimeout;\n  sys_timeout_handler handler;\n  void *arg;\n\n again:\n  if (!next_timeout) {\n    time_needed = sys_arch_mbox_fetch(mbox, msg, 0);\n  } else {\n    if (next_timeout->time > 0) {\n      time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);\n    } else {\n      time_needed = SYS_ARCH_TIMEOUT;\n    }\n\n    if (time_needed == SYS_ARCH_TIMEOUT) {\n      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message\n         could be fetched. We should now call the timeout handler and\n         deallocate the memory allocated for the timeout. */\n      tmptimeout = next_timeout;\n      next_timeout = tmptimeout->next;\n      handler = tmptimeout->h;\n      arg = tmptimeout->arg;\n#if LWIP_DEBUG_TIMERNAMES\n      if (handler != NULL) {\n        LWIP_DEBUGF(TIMERS_DEBUG, (\"stmf calling h=%s arg=%p\\n\",\n          tmptimeout->handler_name, arg));\n      }\n#endif /* LWIP_DEBUG_TIMERNAMES */\n      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);\n      if (handler != NULL) {\n        /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the\n           timeout handler function. */\n        LOCK_TCPIP_CORE();\n        handler(arg);\n        UNLOCK_TCPIP_CORE();\n      }\n      LWIP_TCPIP_THREAD_ALIVE();\n\n      /* We try again to fetch a message from the mbox. */\n      goto again;\n    } else {\n      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout\n         occured. The time variable is set to the number of\n         milliseconds we waited for the message. */\n      if (time_needed < next_timeout->time) {\n        next_timeout->time -= time_needed;\n      } else {\n        next_timeout->time = 0;\n      }\n    }\n  }\n}\n\n#endif /* NO_SYS */\n\n#else /* LWIP_TIMERS */\n/* Satisfy the TCP code which calls this function */\nvoid\ntcp_timer_needed(void)\n{\n}\n#endif /* LWIP_TIMERS */\n"
  },
  {
    "path": "app/lwip/core/udp.c",
    "content": "/**\n * @file\n * User Datagram Protocol module\n *\n */\n\n/*\n * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n * Author: Adam Dunkels <adam@sics.se>\n *\n */\n\n\n/* udp.c\n *\n * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).\n *\n */\n\n/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!\n */\n\n#include \"lwip/opt.h\"\n\n#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */\n\n#include \"lwip/udp.h\"\n#include \"lwip/def.h\"\n#include \"lwip/memp.h\"\n#include \"lwip/inet_chksum.h\"\n#include \"lwip/ip_addr.h\"\n#include \"lwip/netif.h\"\n#include \"lwip/icmp.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/snmp.h\"\n#include \"arch/perf.h\"\n#include \"lwip/dhcp.h\"\n\n#include <string.h>\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\n/* The list of UDP PCBs */\n/* exported in udp.h (was static) */\nstruct udp_pcb *udp_pcbs;\n\n/**\n * Process an incoming UDP datagram.\n *\n * Given an incoming UDP datagram (as a chain of pbufs) this function\n * finds a corresponding UDP PCB and hands over the pbuf to the pcbs\n * recv function. If no pcb is found or the datagram is incorrect, the\n * pbuf is freed.\n *\n * @param p pbuf to be demultiplexed to a UDP PCB.\n * @param inp network interface on which the datagram was received.\n *\n */\nvoid ICACHE_FLASH_ATTR\nudp_input(struct pbuf *p, struct netif *inp)\n{\n  struct udp_hdr *udphdr;\n  struct udp_pcb *pcb, *prev;\n  struct udp_pcb *uncon_pcb;\n  struct ip_hdr *iphdr;\n  u16_t src, dest;\n  u8_t local_match;\n  u8_t broadcast;\n\n  PERF_START;\n\n  UDP_STATS_INC(udp.recv);\n\n  iphdr = (struct ip_hdr *)p->payload;\n\n  /* Check minimum length (IP header + UDP header)\n   * and move payload pointer to UDP header */\n  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {\n    /* drop short packets */\n    LWIP_DEBUGF(UDP_DEBUG,\n                (\"udp_input: short UDP datagram (%\"U16_F\" bytes) discarded\\n\", p->tot_len));\n    UDP_STATS_INC(udp.lenerr);\n    UDP_STATS_INC(udp.drop);\n    snmp_inc_udpinerrors();\n    pbuf_free(p);\n    goto end;\n  }\n\n  udphdr = (struct udp_hdr *)p->payload;\n\n  /* is broadcast packet ? */\n  broadcast = ip_addr_isbroadcast(&current_iphdr_dest, inp);\n\n  LWIP_DEBUGF(UDP_DEBUG, (\"udp_input: received datagram of length %\"U16_F\"\\n\", p->tot_len));\n\n  /* convert src and dest ports to host byte order */\n  src = ntohs(udphdr->src);\n  dest = ntohs(udphdr->dest);\n\n  udp_debug_print(udphdr);\n\n  /* print the UDP source and destination */\n  LWIP_DEBUGF(UDP_DEBUG,\n              (\"udp (%\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\", %\"U16_F\") <-- \"\n               \"(%\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\", %\"U16_F\")\\n\",\n               ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),\n               ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest),\n               ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),\n               ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src)));\n\n#if LWIP_DHCP\n  pcb = NULL;\n  /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by\n     the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */\n  if (dest == DHCP_CLIENT_PORT) {\n    /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */\n    if (src == DHCP_SERVER_PORT) {\n      if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {\n        /* accept the packe if \n           (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!\n           - inp->dhcp->pcb->remote == ANY or iphdr->src */\n        if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||\n           ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &current_iphdr_src))) {\n          pcb = inp->dhcp->pcb;\n        }\n      }\n    } else if (dest == DHCP_SERVER_PORT) {\n      if (src == DHCP_CLIENT_PORT) {\n        if ( inp->dhcps_pcb != NULL ) {\n          if ((ip_addr_isany(&inp->dhcps_pcb->local_ip) ||\n              ip_addr_cmp(&(inp->dhcps_pcb->local_ip), &current_iphdr_dest))) {\n            pcb = inp->dhcps_pcb;\n          }\n        }\n      }\n    }\n  } else\n#endif /* LWIP_DHCP */\n  {\n    prev = NULL;\n    local_match = 0;\n    uncon_pcb = NULL;\n    /* Iterate through the UDP pcb list for a matching pcb.\n     * 'Perfect match' pcbs (connected to the remote port & ip address) are\n     * preferred. If no perfect match is found, the first unconnected pcb that\n     * matches the local port and ip address gets the datagram. */\n    for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {\n      local_match = 0;\n      /* print the PCB local and remote address */\n      LWIP_DEBUGF(UDP_DEBUG,\n                  (\"pcb (%\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\", %\"U16_F\") --- \"\n                   \"(%\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\", %\"U16_F\")\\n\",\n                   ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),\n                   ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port,\n                   ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),\n                   ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));\n\n      /* compare PCB local addr+port to UDP destination addr+port */\n      if ((pcb->local_port == dest) &&\n          ((!broadcast && ip_addr_isany(&pcb->local_ip)) ||\n           ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest) ||\n#if LWIP_IGMP\n           ip_addr_ismulticast(&current_iphdr_dest) ||\n#endif /* LWIP_IGMP */\n#if IP_SOF_BROADCAST_RECV\n           (broadcast && (pcb->so_options & SOF_BROADCAST)))) {\n#else  /* IP_SOF_BROADCAST_RECV */\n           (broadcast))) {\n#endif /* IP_SOF_BROADCAST_RECV */\n        local_match = 1;\n        if ((uncon_pcb == NULL) && \n            ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {\n          /* the first unconnected matching PCB */\n          uncon_pcb = pcb;\n        }\n      }\n      /* compare PCB remote addr+port to UDP source addr+port */\n      if ((local_match != 0) &&\n          (pcb->remote_port == src) &&\n          (ip_addr_isany(&pcb->remote_ip) ||\n           ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src))) {\n        /* the first fully matching PCB */\n        if (prev != NULL) {\n          /* move the pcb to the front of udp_pcbs so that is\n             found faster next time */\n          prev->next = pcb->next;\n          pcb->next = udp_pcbs;\n          udp_pcbs = pcb;\n        } else {\n          UDP_STATS_INC(udp.cachehit);\n        }\n        break;\n      }\n      prev = pcb;\n    }\n    /* no fully matching pcb found? then look for an unconnected pcb */\n    if (pcb == NULL) {\n      pcb = uncon_pcb;\n    }\n  }\n\n  /* Check checksum if this is a match or if it was directed at us. */\n  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &current_iphdr_dest)) {\n    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (\"udp_input: calculating checksum\\n\"));\n#if LWIP_UDPLITE\n    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {\n      /* Do the UDP Lite checksum */\n#if CHECKSUM_CHECK_UDP\n      u16_t chklen = ntohs(udphdr->len);\n      if (chklen < sizeof(struct udp_hdr)) {\n        if (chklen == 0) {\n          /* For UDP-Lite, checksum length of 0 means checksum\n             over the complete packet (See RFC 3828 chap. 3.1) */\n          chklen = p->tot_len;\n        } else {\n          /* At least the UDP-Lite header must be covered by the\n             checksum! (Again, see RFC 3828 chap. 3.1) */\n          UDP_STATS_INC(udp.chkerr);\n          UDP_STATS_INC(udp.drop);\n          snmp_inc_udpinerrors();\n          pbuf_free(p);\n          goto end;\n        }\n      }\n      if (inet_chksum_pseudo_partial(p, &current_iphdr_src, &current_iphdr_dest,\n                             IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {\n       LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n                   (\"udp_input: UDP Lite datagram discarded due to failing checksum\\n\"));\n        UDP_STATS_INC(udp.chkerr);\n        UDP_STATS_INC(udp.drop);\n        snmp_inc_udpinerrors();\n        pbuf_free(p);\n        goto end;\n      }\n#endif /* CHECKSUM_CHECK_UDP */\n    } else\n#endif /* LWIP_UDPLITE */\n    {\n#if CHECKSUM_CHECK_UDP\n      if (udphdr->chksum != 0) {\n        if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),\n                               IP_PROTO_UDP, p->tot_len) != 0) {\n          LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n                      (\"udp_input: UDP datagram discarded due to failing checksum\\n\"));\n          UDP_STATS_INC(udp.chkerr);\n          UDP_STATS_INC(udp.drop);\n          snmp_inc_udpinerrors();\n          pbuf_free(p);\n          goto end;\n        }\n      }\n#endif /* CHECKSUM_CHECK_UDP */\n    }\n    if(pbuf_header(p, -UDP_HLEN)) {\n      /* Can we cope with this failing? Just assert for now */\n      LWIP_ASSERT(\"pbuf_header failed\\n\", 0);\n      UDP_STATS_INC(udp.drop);\n      snmp_inc_udpinerrors();\n      pbuf_free(p);\n      goto end;\n    }\n    if (pcb != NULL) {\n      snmp_inc_udpindatagrams();\n#if SO_REUSE && SO_REUSE_RXTOALL\n      if ((broadcast || ip_addr_ismulticast(&current_iphdr_dest)) &&\n          ((pcb->so_options & SOF_REUSEADDR) != 0)) {\n        /* pass broadcast- or multicast packets to all multicast pcbs\n           if SOF_REUSEADDR is set on the first match */\n        struct udp_pcb *mpcb;\n        u8_t p_header_changed = 0;\n        for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {\n          if (mpcb != pcb) {\n            /* compare PCB local addr+port to UDP destination addr+port */\n            if ((mpcb->local_port == dest) &&\n                ((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||\n                 ip_addr_cmp(&(mpcb->local_ip), &current_iphdr_dest) ||\n#if LWIP_IGMP\n                 ip_addr_ismulticast(&current_iphdr_dest) ||\n#endif /* LWIP_IGMP */\n#if IP_SOF_BROADCAST_RECV\n                 (broadcast && (mpcb->so_options & SOF_BROADCAST)))) {\n#else  /* IP_SOF_BROADCAST_RECV */\n                 (broadcast))) {\n#endif /* IP_SOF_BROADCAST_RECV */\n              /* pass a copy of the packet to all local matches */\n              if (mpcb->recv != NULL) {\n                struct pbuf *q;\n                /* for that, move payload to IP header again */\n                if (p_header_changed == 0) {\n                  pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));\n                  p_header_changed = 1;\n                }\n                q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\n                if (q != NULL) {\n                  err_t err = pbuf_copy(q, p);\n                  if (err == ERR_OK) {\n                    /* move payload to UDP data */\n                    pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));\n                    mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);\n                  }\n                }\n              }\n            }\n          }\n        }\n        if (p_header_changed) {\n          /* and move payload to UDP data again */\n          pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));\n        }\n      }\n#endif /* SO_REUSE && SO_REUSE_RXTOALL */\n      /* callback */\n      if (pcb->recv != NULL) {\n        /* now the recv function is responsible for freeing p */\n        pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);\n      } else {\n        /* no recv function registered? then we have to free the pbuf! */\n        pbuf_free(p);\n        goto end;\n      }\n    } else {\n      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (\"udp_input: not for us.\\n\"));\n\n#if LWIP_ICMP\n      /* No match was found, send ICMP destination port unreachable unless\n         destination address was broadcast/multicast. */\n      if (!broadcast &&\n          !ip_addr_ismulticast(&current_iphdr_dest)) {\n        /* move payload pointer back to ip header */\n        pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);\n        LWIP_ASSERT(\"p->payload == iphdr\", (p->payload == iphdr));\n        icmp_dest_unreach(p, ICMP_DUR_PORT);\n      }\n#endif /* LWIP_ICMP */\n      UDP_STATS_INC(udp.proterr);\n      UDP_STATS_INC(udp.drop);\n      snmp_inc_udpnoports();\n      pbuf_free(p);\n    }\n  } else {\n    pbuf_free(p);\n  }\nend:\n  PERF_STOP(\"udp_input\");\n}\n\n/**\n * Send data using UDP.\n *\n * @param pcb UDP PCB used to send the data.\n * @param p chain of pbuf's to be sent.\n *\n * The datagram will be sent to the current remote_ip & remote_port\n * stored in pcb. If the pcb is not bound to a port, it will\n * automatically be bound to a random port.\n *\n * @return lwIP error code.\n * - ERR_OK. Successful. No error occured.\n * - ERR_MEM. Out of memory.\n * - ERR_RTE. Could not find route to destination address.\n * - More errors could be returned by lower protocol layers.\n *\n * @see udp_disconnect() udp_sendto()\n */\nerr_t ICACHE_FLASH_ATTR\nudp_send(struct udp_pcb *pcb, struct pbuf *p)\n{\n  /* send to the packet using remote ip and port stored in the pcb */\n  return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);\n}\n\n#if LWIP_CHECKSUM_ON_COPY\n/** Same as udp_send() but with checksum\n */\nerr_t ICACHE_FLASH_ATTR\nudp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,\n                u8_t have_chksum, u16_t chksum)\n{\n  /* send to the packet using remote ip and port stored in the pcb */\n  return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port,\n    have_chksum, chksum);\n}\n#endif /* LWIP_CHECKSUM_ON_COPY */\n\n/**\n * Send data to a specified address using UDP.\n *\n * @param pcb UDP PCB used to send the data.\n * @param p chain of pbuf's to be sent.\n * @param dst_ip Destination IP address.\n * @param dst_port Destination UDP port.\n *\n * dst_ip & dst_port are expected to be in the same byte order as in the pcb.\n *\n * If the PCB already has a remote address association, it will\n * be restored after the data is sent.\n * \n * @return lwIP error code (@see udp_send for possible error codes)\n *\n * @see udp_disconnect() udp_send()\n */\nerr_t ICACHE_FLASH_ATTR\nudp_sendto(struct udp_pcb *pcb, struct pbuf *p,\n  ip_addr_t *dst_ip, u16_t dst_port)\n{\n#if LWIP_CHECKSUM_ON_COPY\n  return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0);\n}\n\n/** Same as udp_sendto(), but with checksum */\nerr_t ICACHE_FLASH_ATTR\nudp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,\n                  u16_t dst_port, u8_t have_chksum, u16_t chksum)\n{\n#endif /* LWIP_CHECKSUM_ON_COPY */\n  struct netif *netif;\n\n  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (\"udp_send\\n\"));\n\n  /* find the outgoing network interface for this packet */\n#if LWIP_IGMP\n  netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));\n#else\n  netif = ip_route(dst_ip);\n#endif /* LWIP_IGMP */\n\n  /* no outgoing network interface could be found? */\n  if (netif == NULL) {\n    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (\"udp_send: No route to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n      ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip)));\n    UDP_STATS_INC(udp.rterr);\n    return ERR_RTE;\n  }\n#if LWIP_CHECKSUM_ON_COPY\n  return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);\n#else /* LWIP_CHECKSUM_ON_COPY */\n  return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);\n#endif /* LWIP_CHECKSUM_ON_COPY */\n}\n\n/**\n * Send data to a specified address using UDP.\n * The netif used for sending can be specified.\n *\n * This function exists mainly for DHCP, to be able to send UDP packets\n * on a netif that is still down.\n *\n * @param pcb UDP PCB used to send the data.\n * @param p chain of pbuf's to be sent.\n * @param dst_ip Destination IP address.\n * @param dst_port Destination UDP port.\n * @param netif the netif used for sending.\n *\n * dst_ip & dst_port are expected to be in the same byte order as in the pcb.\n *\n * @return lwIP error code (@see udp_send for possible error codes)\n *\n * @see udp_disconnect() udp_send()\n */\nerr_t ICACHE_FLASH_ATTR\nudp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,\n  ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif)\n{\n#if LWIP_CHECKSUM_ON_COPY\n  return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0);\n}\n\n/** Same as udp_sendto_if(), but with checksum */\nerr_t ICACHE_FLASH_ATTR\nudp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,\n                     u16_t dst_port, struct netif *netif, u8_t have_chksum,\n                     u16_t chksum)\n{\n#endif /* LWIP_CHECKSUM_ON_COPY */\n  struct udp_hdr *udphdr;\n  ip_addr_t *src_ip;\n  err_t err;\n  struct pbuf *q; /* q will be sent down the stack */\n\n#if IP_SOF_BROADCAST\n  /* broadcast filter? */\n  if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {\n    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,\n      (\"udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\\n\", (void *)pcb));\n    return ERR_VAL;\n  }\n#endif /* IP_SOF_BROADCAST */\n\n  /* if the PCB is not yet bound to a port, bind it here */\n  if (pcb->local_port == 0) {\n    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (\"udp_send: not yet bound to a port, binding now\\n\"));\n    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);\n    if (err != ERR_OK) {\n      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"udp_send: forced port bind failed\\n\"));\n      return err;\n    }\n  }\n\n  /* not enough space to add an UDP header to first pbuf in given p chain? */\n  if (pbuf_header(p, UDP_HLEN)) {\n    /* allocate header in a separate new pbuf */\n    q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);\n    /* new header pbuf could not be allocated? */\n    if (q == NULL) {\n      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, (\"udp_send: could not allocate header\\n\"));\n      return ERR_MEM;\n    }\n    if (p->tot_len != 0) {\n      /* chain header q in front of given pbuf p (only if p contains data) */\n      pbuf_chain(q, p);\n    }\n    /* first pbuf q points to header pbuf */\n    LWIP_DEBUGF(UDP_DEBUG,\n                (\"udp_send: added header pbuf %p before given pbuf %p\\n\", (void *)q, (void *)p));\n  } else {\n    /* adding space for header within p succeeded */\n    /* first pbuf q equals given pbuf */\n    q = p;\n    LWIP_DEBUGF(UDP_DEBUG, (\"udp_send: added header in given pbuf %p\\n\", (void *)p));\n  }\n  LWIP_ASSERT(\"check that first pbuf can hold struct udp_hdr\",\n              (q->len >= sizeof(struct udp_hdr)));\n  /* q now represents the packet to be sent */\n  udphdr = (struct udp_hdr *)q->payload;\n  udphdr->src = htons(pcb->local_port);\n  udphdr->dest = htons(dst_port);\n  /* in UDP, 0 checksum means 'no checksum' */\n  udphdr->chksum = 0x0000; \n\n  /* Multicast Loop? */\n#if LWIP_IGMP\n  if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) {\n    q->flags |= PBUF_FLAG_MCASTLOOP;\n  }\n#endif /* LWIP_IGMP */\n\n\n  /* PCB local address is IP_ANY_ADDR? */\n  if (ip_addr_isany(&pcb->local_ip)) {\n    /* use outgoing network interface IP address as source address */\n    src_ip = &(netif->ip_addr);\n  } else {\n    /* check if UDP PCB local IP address is correct\n     * this could be an old address if netif->ip_addr has changed */\n    if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {\n      /* local_ip doesn't match, drop the packet */\n      if (q != p) {\n        /* free the header pbuf */\n        pbuf_free(q);\n        q = NULL;\n        /* p is still referenced by the caller, and will live on */\n      }\n      return ERR_VAL;\n    }\n    /* use UDP PCB local IP address as source address */\n    src_ip = &(pcb->local_ip);\n  }\n\n  LWIP_DEBUGF(UDP_DEBUG, (\"udp_send: sending datagram of length %\"U16_F\"\\n\", q->tot_len));\n\n#if LWIP_UDPLITE\n  /* UDP Lite protocol? */\n  if (pcb->flags & UDP_FLAGS_UDPLITE) {\n    u16_t chklen, chklen_hdr;\n    LWIP_DEBUGF(UDP_DEBUG, (\"udp_send: UDP LITE packet length %\"U16_F\"\\n\", q->tot_len));\n    /* set UDP message length in UDP header */\n    chklen_hdr = chklen = pcb->chksum_len_tx;\n    if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) {\n      if (chklen != 0) {\n        LWIP_DEBUGF(UDP_DEBUG, (\"udp_send: UDP LITE pcb->chksum_len is illegal: %\"U16_F\"\\n\", chklen));\n      }\n      /* For UDP-Lite, checksum length of 0 means checksum\n         over the complete packet. (See RFC 3828 chap. 3.1)\n         At least the UDP-Lite header must be covered by the\n         checksum, therefore, if chksum_len has an illegal\n         value, we generate the checksum over the complete\n         packet to be safe. */\n      chklen_hdr = 0;\n      chklen = q->tot_len;\n    }\n    udphdr->len = htons(chklen_hdr);\n    /* calculate checksum */\n#if CHECKSUM_GEN_UDP\n    udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,\n      IP_PROTO_UDPLITE, q->tot_len,\n#if !LWIP_CHECKSUM_ON_COPY\n      chklen);\n#else /* !LWIP_CHECKSUM_ON_COPY */\n      (have_chksum ? UDP_HLEN : chklen));\n    if (have_chksum) {\n      u32_t acc;\n      acc = udphdr->chksum + (u16_t)~(chksum);\n      udphdr->chksum = FOLD_U32T(acc);\n    }\n#endif /* !LWIP_CHECKSUM_ON_COPY */\n\n    /* chksum zero must become 0xffff, as zero means 'no checksum' */\n    if (udphdr->chksum == 0x0000) {\n      udphdr->chksum = 0xffff;\n    }\n#endif /* CHECKSUM_GEN_UDP */\n    /* output to IP */\n    LWIP_DEBUGF(UDP_DEBUG, (\"udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\\n\"));\n#if LWIP_NETIF_HWADDRHINT\n    netif->addr_hint = &(pcb->addr_hint);\n#endif /* LWIP_NETIF_HWADDRHINT*/\n    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);\n#if LWIP_NETIF_HWADDRHINT\n    netif->addr_hint = NULL;\n#endif /* LWIP_NETIF_HWADDRHINT*/\n  } else\n#endif /* LWIP_UDPLITE */\n  {      /* UDP */\n    LWIP_DEBUGF(UDP_DEBUG, (\"udp_send: UDP packet length %\"U16_F\"\\n\", q->tot_len));\n    udphdr->len = htons(q->tot_len);\n    /* calculate checksum */\n#if CHECKSUM_GEN_UDP\n    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {\n      u16_t udpchksum;\n#if LWIP_CHECKSUM_ON_COPY\n      if (have_chksum) {\n        u32_t acc;\n        udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP,\n          q->tot_len, UDP_HLEN);\n        acc = udpchksum + (u16_t)~(chksum);\n        udpchksum = FOLD_U32T(acc);\n      } else\n#endif /* LWIP_CHECKSUM_ON_COPY */\n      {\n        udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);\n      }\n\n      /* chksum zero must become 0xffff, as zero means 'no checksum' */\n      if (udpchksum == 0x0000) {\n        udpchksum = 0xffff;\n      }\n      udphdr->chksum = udpchksum;\n    }\n#endif /* CHECKSUM_GEN_UDP */\n    LWIP_DEBUGF(UDP_DEBUG, (\"udp_send: UDP checksum 0x%04\"X16_F\"\\n\", udphdr->chksum));\n    LWIP_DEBUGF(UDP_DEBUG, (\"udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\\n\"));\n    /* output to IP */\n#if LWIP_NETIF_HWADDRHINT\n    netif->addr_hint = &(pcb->addr_hint);\n#endif /* LWIP_NETIF_HWADDRHINT*/\n    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);\n#if LWIP_NETIF_HWADDRHINT\n    netif->addr_hint = NULL;\n#endif /* LWIP_NETIF_HWADDRHINT*/\n  }\n  /* TODO: must this be increased even if error occured? */\n  snmp_inc_udpoutdatagrams();\n\n  /* did we chain a separate header pbuf earlier? */\n  if (q != p) {\n    /* free the header pbuf */\n    pbuf_free(q);\n    q = NULL;\n    /* p is still referenced by the caller, and will live on */\n  }\n\n  UDP_STATS_INC(udp.xmit);\n  return err;\n}\n\n/**\n * Bind an UDP PCB.\n *\n * @param pcb UDP PCB to be bound with a local address ipaddr and port.\n * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to\n * bind to all local interfaces.\n * @param port local UDP port to bind with. Use 0 to automatically bind\n * to a random port between UDP_LOCAL_PORT_RANGE_START and\n * UDP_LOCAL_PORT_RANGE_END.\n *\n * ipaddr & port are expected to be in the same byte order as in the pcb.\n *\n * @return lwIP error code.\n * - ERR_OK. Successful. No error occured.\n * - ERR_USE. The specified ipaddr and port are already bound to by\n * another UDP PCB.\n *\n * @see udp_disconnect()\n */\nerr_t ICACHE_FLASH_ATTR\nudp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)\n{\n  struct udp_pcb *ipcb;\n  u8_t rebind;\n\n  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (\"udp_bind(ipaddr = \"));\n  ip_addr_debug_print(UDP_DEBUG, ipaddr);\n  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (\", port = %\"U16_F\")\\n\", port));\n\n  rebind = 0;\n  /* Check for double bind and rebind of the same pcb */\n  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {\n    /* is this UDP PCB already on active list? */\n    if (pcb == ipcb) {\n      /* pcb may occur at most once in active list */\n      LWIP_ASSERT(\"rebind == 0\", rebind == 0);\n      /* pcb already in list, just rebind */\n      rebind = 1;\n    }\n\n    /* By default, we don't allow to bind to a port that any other udp\n       PCB is alread bound to, unless *all* PCBs with that port have tha\n       REUSEADDR flag set. */\n#if SO_REUSE\n    else if (((pcb->so_options & SOF_REUSEADDR) == 0) &&\n             ((ipcb->so_options & SOF_REUSEADDR) == 0)) {\n#else /* SO_REUSE */\n    /* port matches that of PCB in list and REUSEADDR not set -> reject */\n    else {\n#endif /* SO_REUSE */\n      if ((ipcb->local_port == port) &&\n          /* IP address matches, or one is IP_ADDR_ANY? */\n          (ip_addr_isany(&(ipcb->local_ip)) ||\n           ip_addr_isany(ipaddr) ||\n           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {\n        /* other PCB already binds to this local IP and port */\n        LWIP_DEBUGF(UDP_DEBUG,\n                    (\"udp_bind: local port %\"U16_F\" already bound by another pcb\\n\", port));\n        return ERR_USE;\n      }\n    }\n  }\n\n  ip_addr_set(&pcb->local_ip, ipaddr);\n\n  /* no port specified? */\n  if (port == 0) {\n#ifndef UDP_LOCAL_PORT_RANGE_START\n#define UDP_LOCAL_PORT_RANGE_START 4096\n#define UDP_LOCAL_PORT_RANGE_END   0x7fff\n#endif\n    port = UDP_LOCAL_PORT_RANGE_START;\n    ipcb = udp_pcbs;\n    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {\n      if (ipcb->local_port == port) {\n        /* port is already used by another udp_pcb */\n        port++;\n        /* restart scanning all udp pcbs */\n        ipcb = udp_pcbs;\n      } else {\n        /* go on with next udp pcb */\n        ipcb = ipcb->next;\n      }\n    }\n    if (ipcb != NULL) {\n      /* no more ports available in local range */\n      LWIP_DEBUGF(UDP_DEBUG, (\"udp_bind: out of free UDP ports\\n\"));\n      return ERR_USE;\n    }\n  }\n  pcb->local_port = port;\n  snmp_insert_udpidx_tree(pcb);\n  /* pcb not active yet? */\n  if (rebind == 0) {\n    /* place the PCB on the active list if not already there */\n    pcb->next = udp_pcbs;\n    udp_pcbs = pcb;\n  }\n  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n              (\"udp_bind: bound to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\", port %\"U16_F\"\\n\",\n               ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),\n               ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),\n               pcb->local_port));\n  return ERR_OK;\n}\n/**\n * Connect an UDP PCB.\n *\n * This will associate the UDP PCB with the remote address.\n *\n * @param pcb UDP PCB to be connected with remote address ipaddr and port.\n * @param ipaddr remote IP address to connect with.\n * @param port remote UDP port to connect with.\n *\n * @return lwIP error code\n *\n * ipaddr & port are expected to be in the same byte order as in the pcb.\n *\n * The udp pcb is bound to a random local port if not already bound.\n *\n * @see udp_disconnect()\n */\nerr_t ICACHE_FLASH_ATTR\nudp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)\n{\n  struct udp_pcb *ipcb;\n\n  if (pcb->local_port == 0) {\n    err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);\n    if (err != ERR_OK) {\n      return err;\n    }\n  }\n\n  ip_addr_set(&pcb->remote_ip, ipaddr);\n  pcb->remote_port = port;\n  pcb->flags |= UDP_FLAGS_CONNECTED;\n/** TODO: this functionality belongs in upper layers */\n#ifdef LWIP_UDP_TODO\n  /* Nail down local IP for netconn_addr()/getsockname() */\n  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {\n    struct netif *netif;\n\n    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {\n      LWIP_DEBUGF(UDP_DEBUG, (\"udp_connect: No route to 0x%lx\\n\", pcb->remote_ip.addr));\n      UDP_STATS_INC(udp.rterr);\n      return ERR_RTE;\n    }\n    /** TODO: this will bind the udp pcb locally, to the interface which\n        is used to route output packets to the remote address. However, we\n        might want to accept incoming packets on any interface! */\n    pcb->local_ip = netif->ip_addr;\n  } else if (ip_addr_isany(&pcb->remote_ip)) {\n    pcb->local_ip.addr = 0;\n  }\n#endif\n  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\n              (\"udp_connect: connected to %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\",port %\"U16_F\"\\n\",\n               ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),\n               ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),\n               pcb->local_port));\n\n  /* Insert UDP PCB into the list of active UDP PCBs. */\n  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {\n    if (pcb == ipcb) {\n      /* already on the list, just return */\n      return ERR_OK;\n    }\n  }\n  /* PCB not yet on the list, add PCB now */\n  pcb->next = udp_pcbs;\n  udp_pcbs = pcb;\n  return ERR_OK;\n}\n\n/**\n * Disconnect a UDP PCB\n *\n * @param pcb the udp pcb to disconnect.\n */\nvoid ICACHE_FLASH_ATTR\nudp_disconnect(struct udp_pcb *pcb)\n{\n  /* reset remote address association */\n  ip_addr_set_any(&pcb->remote_ip);\n  pcb->remote_port = 0;\n  /* mark PCB as unconnected */\n  pcb->flags &= ~UDP_FLAGS_CONNECTED;\n}\n\n/**\n * Set a receive callback for a UDP PCB\n *\n * This callback will be called when receiving a datagram for the pcb.\n *\n * @param pcb the pcb for wich to set the recv callback\n * @param recv function pointer of the callback function\n * @param recv_arg additional argument to pass to the callback function\n */\nvoid ICACHE_FLASH_ATTR\nudp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)\n{\n  /* remember recv() callback and user data */\n  pcb->recv = recv;\n  pcb->recv_arg = recv_arg;\n}\n\n/**\n * Remove an UDP PCB.\n *\n * @param pcb UDP PCB to be removed. The PCB is removed from the list of\n * UDP PCB's and the data structure is freed from memory.\n *\n * @see udp_new()\n */\nvoid ICACHE_FLASH_ATTR\nudp_remove(struct udp_pcb *pcb)\n{\n  struct udp_pcb *pcb2;\n\n  snmp_delete_udpidx_tree(pcb);\n  /* pcb to be removed is first in list? */\n  if (udp_pcbs == pcb) {\n    /* make list start at 2nd pcb */\n    udp_pcbs = udp_pcbs->next;\n    /* pcb not 1st in list */\n  } else {\n    for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {\n      /* find pcb in udp_pcbs list */\n      if (pcb2->next != NULL && pcb2->next == pcb) {\n        /* remove pcb from list */\n        pcb2->next = pcb->next;\n      }\n    }\n  }\n  memp_free(MEMP_UDP_PCB, pcb);\n}\n\n/**\n * Create a UDP PCB.\n *\n * @return The UDP PCB which was created. NULL if the PCB data structure\n * could not be allocated.\n *\n * @see udp_remove()\n */\nstruct udp_pcb * ICACHE_FLASH_ATTR\nudp_new(void)\n{\n  struct udp_pcb *pcb;\n  pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);\n  /* could allocate UDP PCB? */\n  if (pcb != NULL) {\n    /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0\n     * which means checksum is generated over the whole datagram per default\n     * (recommended as default by RFC 3828). */\n    /* initialize PCB to all zeroes */\n    os_memset(pcb, 0, sizeof(struct udp_pcb));\n    pcb->ttl = UDP_TTL;\n  }\n  return pcb;\n}\n\n#if UDP_DEBUG\n/**\n * Print UDP header information for debug purposes.\n *\n * @param udphdr pointer to the udp header in memory.\n */\nvoid ICACHE_FLASH_ATTR\nudp_debug_print(struct udp_hdr *udphdr)\n{\n  LWIP_DEBUGF(UDP_DEBUG, (\"UDP header:\\n\"));\n  LWIP_DEBUGF(UDP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(UDP_DEBUG, (\"|     %5\"U16_F\"     |     %5\"U16_F\"     | (src port, dest port)\\n\",\n                          ntohs(udphdr->src), ntohs(udphdr->dest)));\n  LWIP_DEBUGF(UDP_DEBUG, (\"+-------------------------------+\\n\"));\n  LWIP_DEBUGF(UDP_DEBUG, (\"|     %5\"U16_F\"     |     0x%04\"X16_F\"    | (len, chksum)\\n\",\n                          ntohs(udphdr->len), ntohs(udphdr->chksum)));\n  LWIP_DEBUGF(UDP_DEBUG, (\"+-------------------------------+\\n\"));\n}\n#endif /* UDP_DEBUG */\n\n#endif /* LWIP_UDP */\n"
  },
  {
    "path": "app/lwip/netif/Makefile",
    "content": "\r\n#############################################################\r\n# Required variables for each makefile\r\n# Discard this section from all parent makefiles\r\n# Expected variables (with automatic defaults):\r\n#   CSRCS (all \"C\" files in the dir)\r\n#   SUBDIRS (all subdirs with a Makefile)\r\n#   GEN_LIBS - list of libs to be generated ()\r\n#   GEN_IMAGES - list of images to be generated ()\r\n#   COMPONENTS_xxx - a list of libs/objs in the form\r\n#     subdir/lib to be extracted and rolled up into\r\n#     a generated lib/image xxx.a ()\r\n#\r\nifndef PDIR\r\n\r\nGEN_LIBS = liblwipnetif.a\r\n\r\nendif\r\n\r\n\r\n#############################################################\r\n# Configuration i.e. compile options etc.\r\n# Target specific stuff (defines etc.) goes in here!\r\n# Generally values applying to a tree are captured in the\r\n#   makefile at its root level - these are then overridden\r\n#   for a subtree within the makefile rooted therein\r\n#\r\n#DEFINES += \r\n\r\n#############################################################\r\n# Recursion Magic - Don't touch this!!\r\n#\r\n# Each subtree potentially has an include directory\r\n#   corresponding to the common APIs applicable to modules\r\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\r\n#   of a module can only contain the include directories up\r\n#   its parent path, and not its siblings\r\n#\r\n# Required for each makefile to inherit from the parent\r\n#\r\n\r\nINCLUDES := $(INCLUDES) -I $(PDIR)include\r\nINCLUDES += -I ./\r\nPDIR := ../$(PDIR)\r\nsinclude $(PDIR)Makefile\r\n\r\n"
  },
  {
    "path": "app/lwip/netif/etharp.c",
    "content": "/**\n * @file\n * Address Resolution Protocol module for IP over Ethernet\n *\n * Functionally, ARP is divided into two parts. The first maps an IP address\n * to a physical address when sending a packet, and the second part answers\n * requests from other machines for our physical address.\n *\n * This implementation complies with RFC 826 (Ethernet ARP). It supports\n * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6\n * if an interface calls etharp_gratuitous(our_netif) upon address change.\n */\n\n/*\n * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\n * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>\n * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n *    this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\n * OF SUCH DAMAGE.\n *\n * This file is part of the lwIP TCP/IP stack.\n *\n */\n \n#include \"lwip/opt.h\"\n\n#if LWIP_ARP || LWIP_ETHERNET\n\n#include \"lwip/ip_addr.h\"\n#include \"lwip/def.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/stats.h\"\n#include \"lwip/snmp.h\"\n#include \"lwip/dhcp.h\"\n#include \"lwip/autoip.h\"\n#include \"netif/etharp.h\"\n\n#if PPPOE_SUPPORT\n#include \"netif/ppp_oe.h\"\n#endif /* PPPOE_SUPPORT */\n\n#include <string.h>\n\n#ifdef MEMLEAK_DEBUG\nstatic const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;\n#endif\n\nconst struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};\nconst struct eth_addr ethzero = {{0,0,0,0,0,0}};\n\n#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */\n\n/** the time an ARP entry stays valid after its last update,\n *  for ARP_TMR_INTERVAL = 5000, this is\n *  (240 * 5) seconds = 20 minutes.\n */\n#define ARP_MAXAGE 240\n/** Re-request a used ARP entry 1 minute before it would expire to prevent\n *  breaking a steadily used connection because the ARP entry timed out. */\n#define ARP_AGE_REREQUEST_USED  (ARP_MAXAGE - 12)\n/** the time an ARP entry stays pending after first request,\n *  for ARP_TMR_INTERVAL = 5000, this is\n *  (2 * 5) seconds = 10 seconds.\n * \n *  @internal Keep this number at least 2, otherwise it might\n *  run out instantly if the timeout occurs directly after a request.\n */\n#define ARP_MAXPENDING 2\n\n#define HWTYPE_ETHERNET 1\n\nenum etharp_state {\n  ETHARP_STATE_EMPTY = 0,\n  ETHARP_STATE_PENDING,\n  ETHARP_STATE_STABLE,\n  ETHARP_STATE_STABLE_REREQUESTING\n};\n\nstruct etharp_entry {\n#if ARP_QUEUEING\n  /** Pointer to queue of pending outgoing packets on this ARP entry. */\n  struct etharp_q_entry *q;\n#else /* ARP_QUEUEING */\n  /** Pointer to a single pending outgoing packet on this ARP entry. */\n  struct pbuf *q;\n#endif /* ARP_QUEUEING */\n  ip_addr_t ipaddr;\n  struct eth_addr ethaddr;\n#if LWIP_SNMP || LWIP_ARP\n  struct netif *netif;\n#endif /* LWIP_SNMP */\n  u8_t state;\n  u8_t ctime;\n#if ETHARP_SUPPORT_STATIC_ENTRIES\n  u8_t static_entry;\n#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */\n};\n\nstatic struct etharp_entry arp_table[ARP_TABLE_SIZE];\n\n#if !LWIP_NETIF_HWADDRHINT\nstatic u8_t etharp_cached_entry;\n#endif /* !LWIP_NETIF_HWADDRHINT */\n\n/** Try hard to create a new entry - we want the IP address to appear in\n    the cache (even if this means removing an active entry or so). */\n#define ETHARP_FLAG_TRY_HARD     1\n#define ETHARP_FLAG_FIND_ONLY    2\n#define ETHARP_FLAG_STATIC_ENTRY 4\n\n#if LWIP_NETIF_HWADDRHINT\n#define ETHARP_SET_HINT(netif, hint)  if (((netif) != NULL) && ((netif)->addr_hint != NULL))  \\\n                                      *((netif)->addr_hint) = (hint);\n#else /* LWIP_NETIF_HWADDRHINT */\n#define ETHARP_SET_HINT(netif, hint)  (etharp_cached_entry = (hint))\n#endif /* LWIP_NETIF_HWADDRHINT */\n\nstatic err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);\n\n\n/* Some checks, instead of etharp_init(): */\n#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))\n  #error \"ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h\"\n#endif\n\n\n#if ARP_QUEUEING\n/**\n * Free a complete queue of etharp entries\n *\n * @param q a qeueue of etharp_q_entry's to free\n */\nstatic void\nfree_etharp_q(struct etharp_q_entry *q)\n{\n  struct etharp_q_entry *r;\n  LWIP_ASSERT(\"q != NULL\", q != NULL);\n  LWIP_ASSERT(\"q->p != NULL\", q->p != NULL);\n  while (q) {\n    r = q;\n    q = q->next;\n    LWIP_ASSERT(\"r->p != NULL\", (r->p != NULL));\n    pbuf_free(r->p);\n    memp_free(MEMP_ARP_QUEUE, r);\n  }\n}\n#else /* ARP_QUEUEING */\n\n/** Compatibility define: free the queued pbuf */\n#define free_etharp_q(q) pbuf_free(q)\n\n#endif /* ARP_QUEUEING */\n\n/** Clean up ARP table entries */\nstatic void ICACHE_FLASH_ATTR\nfree_entry(int i)\n{\n  /* remove from SNMP ARP index tree */\n  snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);\n  /* and empty packet queue */\n  if (arp_table[i].q != NULL) {\n    /* remove all queued packets */\n    LWIP_DEBUGF(ETHARP_DEBUG, (\"etharp_timer: freeing entry %\"U16_F\", packet queue %p.\\n\", (u16_t)i, (void *)(arp_table[i].q)));\n    free_etharp_q(arp_table[i].q);\n    arp_table[i].q = NULL;\n  }\n  /* recycle entry for re-use */      \n  arp_table[i].state = ETHARP_STATE_EMPTY;\n#if ETHARP_SUPPORT_STATIC_ENTRIES\n  arp_table[i].static_entry = 0;\n#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */\n#ifdef LWIP_DEBUG\n  /* for debugging, clean out the complete entry */\n  arp_table[i].ctime = 0;\n#if LWIP_SNMP\n  arp_table[i].netif = NULL;\n#endif /* LWIP_SNMP */\n  ip_addr_set_zero(&arp_table[i].ipaddr);\n  arp_table[i].ethaddr = ethzero;\n#endif /* LWIP_DEBUG */\n}\n\n/**\n * Clears expired entries in the ARP table.\n *\n * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds),\n * in order to expire entries in the ARP table.\n */\nvoid\netharp_tmr(void)\n{\n  u8_t i;\n\n  LWIP_DEBUGF(ETHARP_DEBUG, (\"etharp_timer\\n\"));\n  /* remove expired entries from the ARP table */\n  for (i = 0; i < ARP_TABLE_SIZE; ++i) {\n    u8_t state = arp_table[i].state;\n    if (state != ETHARP_STATE_EMPTY\n#if ETHARP_SUPPORT_STATIC_ENTRIES\n      && (arp_table[i].static_entry == 0)\n#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */\n      ) {\n      arp_table[i].ctime++;\n      if ((arp_table[i].ctime >= ARP_MAXAGE) ||\n          ((arp_table[i].state == ETHARP_STATE_PENDING)  &&\n           (arp_table[i].ctime >= ARP_MAXPENDING))) {\n        /* pending or stable entry has become old! */\n        LWIP_DEBUGF(ETHARP_DEBUG, (\"etharp_timer: expired %s entry %\"U16_F\".\\n\",\n             arp_table[i].state >= ETHARP_STATE_STABLE ? \"stable\" : \"pending\", (u16_t)i));\n        /* clean up entries that have just been expired */\n        free_entry(i);\n      }\n      else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) {\n        /* Reset state to stable, so that the next transmitted packet will\n           re-send an ARP request. */\n        arp_table[i].state = ETHARP_STATE_STABLE;\n      }\n#if ARP_QUEUEING\n      /* still pending entry? (not expired) */\n      if (arp_table[i].state == ETHARP_STATE_PENDING) {\n        /* resend an ARP query here? */\n      }\n#endif /* ARP_QUEUEING */\n    }\n  }\n}\n\n/**\n * Search the ARP table for a matching or new entry.\n * \n * If an IP address is given, return a pending or stable ARP entry that matches\n * the address. If no match is found, create a new entry with this address set,\n * but in state ETHARP_EMPTY. The caller must check and possibly change the\n * state of the returned entry.\n * \n * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.\n * \n * In all cases, attempt to create new entries from an empty entry. If no\n * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle\n * old entries. Heuristic choose the least important entry for recycling.\n *\n * @param ipaddr IP address to find in ARP cache, or to add if not found.\n * @param flags @see definition of ETHARP_FLAG_*\n * @param netif netif related to this address (used for NETIF_HWADDRHINT)\n *  \n * @return The ARP entry index that matched or is created, ERR_MEM if no\n * entry is found or could be recycled.\n */\nstatic s8_t ICACHE_FLASH_ATTR\nfind_entry(ip_addr_t *ipaddr, u8_t flags)\n{\n  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;\n  s8_t empty = ARP_TABLE_SIZE;\n  u8_t i = 0, age_pending = 0, age_stable = 0;\n  /* oldest entry with packets on queue */\n  s8_t old_queue = ARP_TABLE_SIZE;\n  /* its age */\n  u8_t age_queue = 0;\n\n  /**\n   * a) do a search through the cache, remember candidates\n   * b) select candidate entry\n   * c) create new entry\n   */\n\n  /* a) in a single search sweep, do all of this\n   * 1) remember the first empty entry (if any)\n   * 2) remember the oldest stable entry (if any)\n   * 3) remember the oldest pending entry without queued packets (if any)\n   * 4) remember the oldest pending entry with queued packets (if any)\n   * 5) search for a matching IP entry, either pending or stable\n   *    until 5 matches, or all entries are searched for.\n   */\n\n  for (i = 0; i < ARP_TABLE_SIZE; ++i) {\n    u8_t state = arp_table[i].state;\n    /* no empty entry found yet and now we do find one? */\n    if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {\n      LWIP_DEBUGF(ETHARP_DEBUG, (\"find_entry: found empty entry %\"U16_F\"\\n\", (u16_t)i));\n      /* remember first empty entry */\n      empty = i;\n    } else if (state != ETHARP_STATE_EMPTY) {\n      LWIP_ASSERT(\"state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE\",\n        state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE);\n      /* if given, does IP address match IP address in ARP entry? */\n      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {\n        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"find_entry: found matching entry %\"U16_F\"\\n\", (u16_t)i));\n        /* found exact IP address match, simply bail out */\n        return i;\n      }\n      /* pending entry? */\n      if (state == ETHARP_STATE_PENDING) {\n        /* pending with queued packets? */\n        if (arp_table[i].q != NULL) {\n          if (arp_table[i].ctime >= age_queue) {\n            old_queue = i;\n            age_queue = arp_table[i].ctime;\n          }\n        } else\n        /* pending without queued packets? */\n        {\n          if (arp_table[i].ctime >= age_pending) {\n            old_pending = i;\n            age_pending = arp_table[i].ctime;\n          }\n        }\n      /* stable entry? */\n      } else if (state >= ETHARP_STATE_STABLE) {\n#if ETHARP_SUPPORT_STATIC_ENTRIES\n        /* don't record old_stable for static entries since they never expire */\n        if (arp_table[i].static_entry == 0)\n#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */\n        {\n          /* remember entry with oldest stable entry in oldest, its age in maxtime */\n          if (arp_table[i].ctime >= age_stable) {\n            old_stable = i;\n            age_stable = arp_table[i].ctime;\n          }\n        }\n      }\n    }\n  }\n  /* { we have no match } => try to create a new entry */\n   \n  /* don't create new entry, only search? */\n  if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||\n      /* or no empty entry found and not allowed to recycle? */\n      ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"find_entry: no empty entry found and not allowed to recycle\\n\"));\n    return (s8_t)ERR_MEM;\n  }\n  \n  /* b) choose the least destructive entry to recycle:\n   * 1) empty entry\n   * 2) oldest stable entry\n   * 3) oldest pending entry without queued packets\n   * 4) oldest pending entry with queued packets\n   * \n   * { ETHARP_FLAG_TRY_HARD is set at this point }\n   */ \n\n  /* 1) empty entry available? */\n  if (empty < ARP_TABLE_SIZE) {\n    i = empty;\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"find_entry: selecting empty entry %\"U16_F\"\\n\", (u16_t)i));\n  } else {\n    /* 2) found recyclable stable entry? */\n    if (old_stable < ARP_TABLE_SIZE) {\n      /* recycle oldest stable*/\n      i = old_stable;\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"find_entry: selecting oldest stable entry %\"U16_F\"\\n\", (u16_t)i));\n      /* no queued packets should exist on stable entries */\n      LWIP_ASSERT(\"arp_table[i].q == NULL\", arp_table[i].q == NULL);\n    /* 3) found recyclable pending entry without queued packets? */\n    } else if (old_pending < ARP_TABLE_SIZE) {\n      /* recycle oldest pending */\n      i = old_pending;\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"find_entry: selecting oldest pending entry %\"U16_F\" (without queue)\\n\", (u16_t)i));\n    /* 4) found recyclable pending entry with queued packets? */\n    } else if (old_queue < ARP_TABLE_SIZE) {\n      /* recycle oldest pending (queued packets are free in free_entry) */\n      i = old_queue;\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"find_entry: selecting oldest pending entry %\"U16_F\", freeing packet queue %p\\n\", (u16_t)i, (void *)(arp_table[i].q)));\n      /* no empty or recyclable entries found */\n    } else {\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"find_entry: no empty or recyclable entries found\\n\"));\n      return (s8_t)ERR_MEM;\n    }\n\n    /* { empty or recyclable entry found } */\n    LWIP_ASSERT(\"i < ARP_TABLE_SIZE\", i < ARP_TABLE_SIZE);\n    free_entry(i);\n  }\n\n  LWIP_ASSERT(\"i < ARP_TABLE_SIZE\", i < ARP_TABLE_SIZE);\n  LWIP_ASSERT(\"arp_table[i].state == ETHARP_STATE_EMPTY\",\n    arp_table[i].state == ETHARP_STATE_EMPTY);\n\n  /* IP address given? */\n  if (ipaddr != NULL) {\n    /* set IP address */\n    ip_addr_copy(arp_table[i].ipaddr, *ipaddr);\n  }\n  arp_table[i].ctime = 0;\n#if ETHARP_SUPPORT_STATIC_ENTRIES\n  arp_table[i].static_entry = 0;\n#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */\n  return (err_t)i;\n}\n\n/**\n * Send an IP packet on the network using netif->linkoutput\n * The ethernet header is filled in before sending.\n *\n * @params netif the lwIP network interface on which to send the packet\n * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header\n * @params src the source MAC address to be copied into the ethernet header\n * @params dst the destination MAC address to be copied into the ethernet header\n * @return ERR_OK if the packet was sent, any other err_t on failure\n */\nstatic err_t ICACHE_FLASH_ATTR\netharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)\n{\n  struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;\n\n  LWIP_ASSERT(\"netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!\",\n              (netif->hwaddr_len == ETHARP_HWADDR_LEN));\n  ETHADDR32_COPY(&ethhdr->dest, dst);\n  ETHADDR16_COPY(&ethhdr->src, src);\n  ethhdr->type = PP_HTONS(ETHTYPE_IP);\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_send_ip: sending packet %p\\n\", (void *)p));\n  /* send the packet */\n  return netif->linkoutput(netif, p);\n}\n\n/**\n * Update (or insert) a IP/MAC address pair in the ARP cache.\n *\n * If a pending entry is resolved, any queued packets will be sent\n * at this point.\n * \n * @param netif netif related to this entry (used for NETIF_ADDRHINT)\n * @param ipaddr IP address of the inserted ARP entry.\n * @param ethaddr Ethernet address of the inserted ARP entry.\n * @param flags @see definition of ETHARP_FLAG_*\n *\n * @return\n * - ERR_OK Succesfully updated ARP cache.\n * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set.\n * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.\n *\n * @see pbuf_free()\n */\nstatic err_t ICACHE_FLASH_ATTR\nupdate_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)\n{\n  s8_t i;\n  LWIP_ASSERT(\"netif->hwaddr_len == ETHARP_HWADDR_LEN\", netif->hwaddr_len == ETHARP_HWADDR_LEN);\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"update_arp_entry: %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\" - %02\"X16_F\":%02\"X16_F\":%02\"X16_F\":%02\"X16_F\":%02\"X16_F\":%02\"X16_F\"\\n\",\n    ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),\n    ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],\n    ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));\n  /* non-unicast address? */\n  if (ip_addr_isany(ipaddr) ||\n      ip_addr_isbroadcast(ipaddr, netif) ||\n      ip_addr_ismulticast(ipaddr)) {\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"update_arp_entry: will not add non-unicast IP address to ARP cache\\n\"));\n    return ERR_ARG;\n  }\n  /* find or create ARP entry */\n  i = find_entry(ipaddr, flags);\n  /* bail out if no entry could be found */\n  if (i < 0) {\n    return (err_t)i;\n  }\n\n#if ETHARP_SUPPORT_STATIC_ENTRIES\n  if (flags & ETHARP_FLAG_STATIC_ENTRY) {\n    /* record static type */\n    arp_table[i].static_entry = 1;\n  }\n#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */\n\n  /* mark it stable */\n  arp_table[i].state = ETHARP_STATE_STABLE;\n\n#if LWIP_SNMP\n  /* record network interface */\n  arp_table[i].netif = netif;\n#endif /* LWIP_SNMP */\n  /* insert in SNMP ARP index tree */\n  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);\n\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"update_arp_entry: updating stable entry %\"S16_F\"\\n\", (s16_t)i));\n  /* update address */\n  ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);\n  /* reset time stamp */\n  arp_table[i].ctime = 0;\n  /* this is where we will send out queued packets! */\n#if ARP_QUEUEING\n  while (arp_table[i].q != NULL) {\n    struct pbuf *p;\n    /* remember remainder of queue */\n    struct etharp_q_entry *q = arp_table[i].q;\n    /* pop first item off the queue */\n    arp_table[i].q = q->next;\n    /* get the packet pointer */\n    p = q->p;\n    /* now queue entry can be freed */\n    memp_free(MEMP_ARP_QUEUE, q);\n#else /* ARP_QUEUEING */\n  if (arp_table[i].q != NULL) {\n    struct pbuf *p = arp_table[i].q;\n    arp_table[i].q = NULL;\n#endif /* ARP_QUEUEING */\n    /* send the queued IP packet */\n    etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);\n    /* free the queued IP packet */\n    pbuf_free(p);\n  }\n  return ERR_OK;\n}\n\n#if ETHARP_SUPPORT_STATIC_ENTRIES\n/** Add a new static entry to the ARP table. If an entry exists for the\n * specified IP address, this entry is overwritten.\n * If packets are queued for the specified IP address, they are sent out.\n *\n * @param ipaddr IP address for the new static entry\n * @param ethaddr ethernet address for the new static entry\n * @return @see return values of etharp_add_static_entry\n */\nerr_t\netharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)\n{\n  struct netif *netif;\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_add_static_entry: %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\" - %02\"X16_F\":%02\"X16_F\":%02\"X16_F\":%02\"X16_F\":%02\"X16_F\":%02\"X16_F\"\\n\",\n    ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),\n    ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],\n    ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));\n\n  netif = ip_route(ipaddr);\n  if (netif == NULL) {\n    return ERR_RTE;\n  }\n\n  return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);\n}\n\n/** Remove a static entry from the ARP table previously added with a call to\n * etharp_add_static_entry.\n *\n * @param ipaddr IP address of the static entry to remove\n * @return ERR_OK: entry removed\n *         ERR_MEM: entry wasn't found\n *         ERR_ARG: entry wasn't a static entry but a dynamic one\n */\nerr_t\netharp_remove_static_entry(ip_addr_t *ipaddr)\n{\n  s8_t i;\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_remove_static_entry: %\"U16_F\".%\"U16_F\".%\"U16_F\".%\"U16_F\"\\n\",\n    ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));\n\n  /* find or create ARP entry */\n  i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);\n  /* bail out if no entry could be found */\n  if (i < 0) {\n    return (err_t)i;\n  }\n\n  if ((arp_table[i].state != ETHARP_STATE_STABLE) ||\n    (arp_table[i].static_entry == 0)) {\n    /* entry wasn't a static entry, cannot remove it */\n    return ERR_ARG;\n  }\n  /* entry found, free it */\n  free_entry(i);\n  return ERR_OK;\n}\n#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */\n\n/**\n * Remove all ARP table entries of the specified netif.\n *\n * @param netif points to a network interface\n */\nvoid ICACHE_FLASH_ATTR etharp_cleanup_netif(struct netif *netif)\n{\n  u8_t i;\n\n  for (i = 0; i < ARP_TABLE_SIZE; ++i) {\n    u8_t state = arp_table[i].state;\n    if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) {\n      free_entry(i);\n    }\n  }\n}\n\n/**\n * Finds (stable) ethernet/IP address pair from ARP table\n * using interface and IP address index.\n * @note the addresses in the ARP table are in network order!\n *\n * @param netif points to interface index\n * @param ipaddr points to the (network order) IP address index\n * @param eth_ret points to return pointer\n * @param ip_ret points to return pointer\n * @return table index if found, -1 otherwise\n */\ns8_t\netharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,\n         struct eth_addr **eth_ret, ip_addr_t **ip_ret)\n{\n  s8_t i;\n\n  LWIP_ASSERT(\"eth_ret != NULL && ip_ret != NULL\",\n    eth_ret != NULL && ip_ret != NULL);\n\n  LWIP_UNUSED_ARG(netif);\n\n  i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);\n  if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) {\n      *eth_ret = &arp_table[i].ethaddr;\n      *ip_ret = &arp_table[i].ipaddr;\n      return i;\n  }\n  return -1;\n}\n\n#if ETHARP_TRUST_IP_MAC\n/**\n * Updates the ARP table using the given IP packet.\n *\n * Uses the incoming IP packet's source address to update the\n * ARP cache for the local network. The function does not alter\n * or free the packet. This function must be called before the\n * packet p is passed to the IP layer.\n *\n * @param netif The lwIP network interface on which the IP packet pbuf arrived.\n * @param p The IP packet that arrived on netif.\n *\n * @return NULL\n *\n * @see pbuf_free()\n */\nstatic void ICACHE_FLASH_ATTR\netharp_ip_input(struct netif *netif, struct pbuf *p)\n{\n  struct eth_hdr *ethhdr;\n  struct ip_hdr *iphdr;\n  ip_addr_t iphdr_src;\n  LWIP_ERROR(\"netif != NULL\", (netif != NULL), return;);\n\n  /* Only insert an entry if the source IP address of the\n     incoming IP packet comes from a host on the local network. */\n  ethhdr = (struct eth_hdr *)p->payload;\n  iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);\n#if ETHARP_SUPPORT_VLAN\n  if (ethhdr->type == ETHTYPE_VLAN) {\n    iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);\n  }\n#endif /* ETHARP_SUPPORT_VLAN */\n\n  ip_addr_copy(iphdr_src, iphdr->src);\n\n  /* source is not on the local network? */\n  if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) {\n    /* do nothing */\n    return;\n  }\n\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_ip_input: updating ETHARP table.\\n\"));\n  /* update the source IP address in the cache, if present */\n  /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk\n   * back soon (for example, if the destination IP address is ours. */\n  update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);\n}\n#endif /* ETHARP_TRUST_IP_MAC */\n\n/**\n * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache  \n * send out queued IP packets. Updates cache with snooped address pairs.\n *\n * Should be called for incoming ARP packets. The pbuf in the argument\n * is freed by this function.\n *\n * @param netif The lwIP network interface on which the ARP packet pbuf arrived.\n * @param ethaddr Ethernet address of netif.\n * @param p The ARP packet that arrived on netif. Is freed by this function.\n *\n * @return NULL\n *\n * @see pbuf_free()\n */\nstatic void ICACHE_FLASH_ATTR\netharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)\n{\n  struct etharp_hdr *hdr;\n  struct eth_hdr *ethhdr;\n  /* these are aligned properly, whereas the ARP header fields might not be */\n  ip_addr_t sipaddr, dipaddr;\n  u8_t for_us;\n#if LWIP_AUTOIP\n  const u8_t * ethdst_hwaddr;\n#endif /* LWIP_AUTOIP */\n#ifdef EBUF_LWIP\n  struct pbuf *q;\n#endif /* EBUF_LWIP */\n\n  LWIP_ERROR(\"netif != NULL\", (netif != NULL), return;);\n\n  /* drop short ARP packets: we have to check for p->len instead of p->tot_len here\n     since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */\n  if (p->len < SIZEOF_ETHARP_PACKET) {\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,\n      (\"etharp_arp_input: packet dropped, too short (%\"S16_F\"/%\"S16_F\")\\n\", p->tot_len,\n      (s16_t)SIZEOF_ETHARP_PACKET));\n    ETHARP_STATS_INC(etharp.lenerr);\n    ETHARP_STATS_INC(etharp.drop);\n    pbuf_free(p);\n    return;\n  }\n\n  ethhdr = (struct eth_hdr *)p->payload;\n  hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);\n#if ETHARP_SUPPORT_VLAN\n  if (ethhdr->type == ETHTYPE_VLAN) {\n    hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);\n  }\n#endif /* ETHARP_SUPPORT_VLAN */\n\n  /* RFC 826 \"Packet Reception\": */\n  if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||\n      (hdr->hwlen != ETHARP_HWADDR_LEN) ||\n      (hdr->protolen != sizeof(ip_addr_t)) ||\n      (hdr->proto != PP_HTONS(ETHTYPE_IP)) ||\n      (ethhdr->type != PP_HTONS(ETHTYPE_ARP)))  {\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,\n      (\"etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%\"U16_F\"/%\"U16_F\"/%\"U16_F\"/%\"U16_F\"/%\"U16_F\")\\n\",\n      hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen, ethhdr->type));\n    ETHARP_STATS_INC(etharp.proterr);\n    ETHARP_STATS_INC(etharp.drop);\n    pbuf_free(p);\n    return;\n  }\n  ETHARP_STATS_INC(etharp.recv);\n\n#if LWIP_AUTOIP\n  /* We have to check if a host already has configured our random\n   * created link local address and continously check if there is\n   * a host with this IP-address so we can detect collisions */\n  autoip_arp_reply(netif, hdr);\n#endif /* LWIP_AUTOIP */\n\n  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without\n   * structure packing (not using structure copy which breaks strict-aliasing rules). */\n  IPADDR2_COPY(&sipaddr, &hdr->sipaddr);\n  IPADDR2_COPY(&dipaddr, &hdr->dipaddr);\n\n  /* this interface is not configured? */\n  if (ip_addr_isany(&netif->ip_addr)) {\n    for_us = 0;\n  } else {\n    /* ARP packet directed to us? */\n    for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr));\n  }\n\n  /* ARP message directed to us?\n      -> add IP address in ARP cache; assume requester wants to talk to us,\n         can result in directly sending the queued packets for this host.\n     ARP message not directed to us?\n      ->  update the source IP address in the cache, if present */\n  update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),\n                   for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);\n\n  /* now act on the message itself */\n  switch (hdr->opcode) {\n  /* ARP request? */\n  case PP_HTONS(ARP_REQUEST):\n    /* ARP request. If it asked for our address, we send out a\n     * reply. In any case, we time-stamp any existing ARP entry,\n     * and possiby send out an IP packet that was queued on it. */\n\n    LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_arp_input: incoming ARP request\\n\"));\n    /* ARP request for our address? */\n    if (for_us) {\n\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_arp_input: replying to ARP request for our IP address\\n\"));\n      /* Re-use pbuf to send ARP reply.\n         Since we are re-using an existing pbuf, we can't call etharp_raw since\n         that would allocate a new pbuf. */\n      hdr->opcode = htons(ARP_REPLY);\n\n      IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr);\n      IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr);\n\n      LWIP_ASSERT(\"netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!\",\n                  (netif->hwaddr_len == ETHARP_HWADDR_LEN));\n#if LWIP_AUTOIP\n      /* If we are using Link-Local, all ARP packets that contain a Link-Local\n       * 'sender IP address' MUST be sent using link-layer broadcast instead of\n       * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */\n      ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr;\n#endif /* LWIP_AUTOIP */\n\n      ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr);\n#if LWIP_AUTOIP\n      ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);\n#else  /* LWIP_AUTOIP */\n      ETHADDR16_COPY(&ethhdr->dest, &hdr->shwaddr);\n#endif /* LWIP_AUTOIP */\n      ETHADDR16_COPY(&hdr->shwaddr, ethaddr);\n      ETHADDR16_COPY(&ethhdr->src, ethaddr);\n\n      /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header\n         are already correct, we tested that before */\n#ifdef EBUF_LWIP\n      /*\n       *   don't do flip-flop here... do a copy here.\n       *    otherwise, we need to handle existing pbuf->eb in ieee80211_output.c\n       */\n      \n      q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\n      if (q != NULL) {\n          pbuf_copy(q, p);\n          //pbuf_free(p);\n      } else {\n          LWIP_ASSERT(\"q != NULL\", q != NULL);\n      }\n\n      netif->linkoutput(netif, q);\n      pbuf_free(q);\n#else\n\n      /* return ARP reply */\n      netif->linkoutput(netif, p);\n#endif /* ESF_LWIP */\n    /* we are not configured? */\n    } else if (ip_addr_isany(&netif->ip_addr)) {\n      /* { for_us == 0 and netif->ip_addr.addr == 0 } */\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_arp_input: we are unconfigured, ARP request ignored.\\n\"));\n    /* request was not directed to us */\n    } else {\n      /* { for_us == 0 and netif->ip_addr.addr != 0 } */\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_arp_input: ARP request was not for us.\\n\"));\n    }\n    break;\n  case PP_HTONS(ARP_REPLY):\n    /* ARP reply. We already updated the ARP cache earlier. */\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_arp_input: incoming ARP reply\\n\"));\n#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)\n    /* DHCP wants to know about ARP replies from any host with an\n     * IP address also offered to us by the DHCP server. We do not\n     * want to take a duplicate IP address on a single network.\n     * @todo How should we handle redundant (fail-over) interfaces? */\n    dhcp_arp_reply(netif, &sipaddr);\n#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */\n    break;\n  default:\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_arp_input: ARP unknown opcode type %\"S16_F\"\\n\", htons(hdr->opcode)));\n    ETHARP_STATS_INC(etharp.err);\n    break;\n  }\n  /* free ARP packet */\n  pbuf_free(p);\n}\n\n/** Just a small helper function that sends a pbuf to an ethernet address\n * in the arp_table specified by the index 'arp_idx'.\n */\nstatic err_t ICACHE_FLASH_ATTR\netharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)\n{\n  LWIP_ASSERT(\"arp_table[arp_idx].state >= ETHARP_STATE_STABLE\",\n              arp_table[arp_idx].state >= ETHARP_STATE_STABLE);\n  /* if arp table entry is about to expire: re-request it,\n     but only if its state is ETHARP_STATE_STABLE to prevent flooding the\n     network with ARP requests if this address is used frequently. */\n  if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) && \n      (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) {\n    if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) {\n      arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING;\n    }\n  }\n  \n  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),\n    &arp_table[arp_idx].ethaddr);\n}\n\n/**\n * Resolve and fill-in Ethernet address header for outgoing IP packet.\n *\n * For IP multicast and broadcast, corresponding Ethernet addresses\n * are selected and the packet is transmitted on the link.\n *\n * For unicast addresses, the packet is submitted to etharp_query(). In\n * case the IP address is outside the local network, the IP address of\n * the gateway is used.\n *\n * @param netif The lwIP network interface which the IP packet will be sent on.\n * @param q The pbuf(s) containing the IP packet to be sent.\n * @param ipaddr The IP address of the packet destination.\n *\n * @return\n * - ERR_RTE No route to destination (no gateway to external networks),\n * or the return type of either etharp_query() or etharp_send_ip().\n */\nerr_t\netharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)\n{\n  struct eth_addr *dest, mcastaddr;\n\n  /* make room for Ethernet header - should not fail */\n  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {\n    /* bail out */\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,\n      (\"etharp_output: could not allocate room for header.\\n\"));\n    LINK_STATS_INC(link.lenerr);\n    return ERR_BUF;\n  }\n\n  /* assume unresolved Ethernet address */\n  dest = NULL;\n  /* Determine on destination hardware address. Broadcasts and multicasts\n   * are special, other IP addresses are looked up in the ARP table. */\n\n  /* broadcast destination IP address? */\n  if (ip_addr_isbroadcast(ipaddr, netif)) {\n    /* broadcast on Ethernet also */\n    dest = (struct eth_addr *)&ethbroadcast;\n  /* multicast destination IP address? */\n  } else if (ip_addr_ismulticast(ipaddr)) {\n    /* Hash IP multicast address to MAC address.*/\n    mcastaddr.addr[0] = 0x01;\n    mcastaddr.addr[1] = 0x00;\n    mcastaddr.addr[2] = 0x5e;\n    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;\n    mcastaddr.addr[4] = ip4_addr3(ipaddr);\n    mcastaddr.addr[5] = ip4_addr4(ipaddr);\n    /* destination Ethernet address is multicast */\n    dest = &mcastaddr;\n  /* unicast destination IP address? */\n  } else {\n    s8_t i;\n    /* outside local network? if so, this can neither be a global broadcast nor\n       a subnet broadcast. */\n    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&\n        !ip_addr_islinklocal(ipaddr)) {\n#if LWIP_AUTOIP\n      struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload +\n        sizeof(struct eth_hdr));\n      /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with\n         a link-local source address must always be \"directly to its destination\n         on the same physical link. The host MUST NOT send the packet to any\n         router for forwarding\". */\n      if (!ip_addr_islinklocal(&iphdr->src))\n#endif /* LWIP_AUTOIP */\n      {\n        /* interface has default gateway? */\n        if (!ip_addr_isany(&netif->gw)) {\n          /* send to hardware address of default gateway IP address */\n          ipaddr = &(netif->gw);\n        /* no default gateway available */\n        } else {\n          /* no route to destination error (default gateway missing) */\n          return ERR_RTE;\n        }\n      }\n    }\n#if LWIP_NETIF_HWADDRHINT\n    if (netif->addr_hint != NULL) {\n      /* per-pcb cached entry was given */\n      u8_t etharp_cached_entry = *(netif->addr_hint);\n      if (etharp_cached_entry < ARP_TABLE_SIZE) {\n#endif /* LWIP_NETIF_HWADDRHINT */\n        if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&\n            (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) {\n          /* the per-pcb-cached entry is stable and the right one! */\n          ETHARP_STATS_INC(etharp.cachehit);\n          return etharp_output_to_arp_index(netif, q, etharp_cached_entry);\n        }\n#if LWIP_NETIF_HWADDRHINT\n      }\n    }\n#endif /* LWIP_NETIF_HWADDRHINT */\n    /* find stable entry: do this here since this is a critical path for\n       throughput and etharp_find_entry() is kind of slow */\n    for (i = 0; i < ARP_TABLE_SIZE; i++) {\n      if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&\n          (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr))) {\n        /* found an existing, stable entry */\n        ETHARP_SET_HINT(netif, i);\n        return etharp_output_to_arp_index(netif, q, i);\n      }\n    }\n    /* queue on destination Ethernet address belonging to ipaddr */\n    return etharp_query(netif, ipaddr, q);\n  }\n\n  /* continuation for multicast/broadcast destinations */\n  /* obtain source Ethernet address of the given interface */\n  /* send packet directly on the link */\n  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);\n}\n\n/**\n * Send an ARP request for the given IP address and/or queue a packet.\n *\n * If the IP address was not yet in the cache, a pending ARP cache entry\n * is added and an ARP request is sent for the given address. The packet\n * is queued on this entry.\n *\n * If the IP address was already pending in the cache, a new ARP request\n * is sent for the given address. The packet is queued on this entry.\n *\n * If the IP address was already stable in the cache, and a packet is\n * given, it is directly sent and no ARP request is sent out. \n * \n * If the IP address was already stable in the cache, and no packet is\n * given, an ARP request is sent out.\n * \n * @param netif The lwIP network interface on which ipaddr\n * must be queried for.\n * @param ipaddr The IP address to be resolved.\n * @param q If non-NULL, a pbuf that must be delivered to the IP address.\n * q is not freed by this function.\n *\n * @note q must only be ONE packet, not a packet queue!\n *\n * @return\n * - ERR_BUF Could not make room for Ethernet header.\n * - ERR_MEM Hardware address unknown, and no more ARP entries available\n *   to query for address or queue the packet.\n * - ERR_MEM Could not queue packet due to memory shortage.\n * - ERR_RTE No route to destination (no gateway to external networks).\n * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.\n *\n */\nerr_t\netharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)\n{\n  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;\n  err_t result = ERR_MEM;\n  s8_t i; /* ARP entry index */\n\n  /* non-unicast address? */\n  if (ip_addr_isbroadcast(ipaddr, netif) ||\n      ip_addr_ismulticast(ipaddr) ||\n      ip_addr_isany(ipaddr)) {\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_query: will not add non-unicast IP address to ARP cache\\n\"));\n    return ERR_ARG;\n  }\n\n  /* find entry in ARP cache, ask to create entry if queueing packet */\n  i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);\n\n  /* could not find or create entry? */\n  if (i < 0) {\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_query: could not create ARP entry\\n\"));\n    if (q) {\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_query: packet dropped\\n\"));\n      ETHARP_STATS_INC(etharp.memerr);\n    }\n    return (err_t)i;\n  }\n\n  /* mark a fresh entry as pending (we just sent a request) */\n  if (arp_table[i].state == ETHARP_STATE_EMPTY) {\n    arp_table[i].state = ETHARP_STATE_PENDING;\n  }\n\n  /* { i is either a STABLE or (new or existing) PENDING entry } */\n  LWIP_ASSERT(\"arp_table[i].state == PENDING or STABLE\",\n  ((arp_table[i].state == ETHARP_STATE_PENDING) ||\n   (arp_table[i].state >= ETHARP_STATE_STABLE)));\n\n  /* do we have a pending entry? or an implicit query request? */\n  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {\n    /* try to resolve it; send out ARP request */\n    result = etharp_request(netif, ipaddr);\n    if (result != ERR_OK) {\n      /* ARP request couldn't be sent */\n      /* We don't re-send arp request in etharp_tmr, but we still queue packets,\n         since this failure could be temporary, and the next packet calling\n         etharp_query again could lead to sending the queued packets. */\n    }\n    if (q == NULL) {\n      return result;\n    }\n  }\n\n  /* packet given? */\n  LWIP_ASSERT(\"q != NULL\", q != NULL);\n  /* stable entry? */\n  if (arp_table[i].state >= ETHARP_STATE_STABLE) {\n    /* we have a valid IP->Ethernet address mapping */\n    ETHARP_SET_HINT(netif, i);\n    /* send the packet */\n    result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));\n  /* pending entry? (either just created or already pending */\n  } else if (arp_table[i].state == ETHARP_STATE_PENDING) {\n    /* entry is still pending, queue the given packet 'q' */\n    struct pbuf *p;\n    int copy_needed = 0;\n    /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but\n     * to copy the whole queue into a new PBUF_RAM (see bug #11400) \n     * PBUF_ROMs can be left as they are, since ROM must not get changed. */\n    p = q;\n    while (p) {\n      LWIP_ASSERT(\"no packet queues allowed!\", (p->len != p->tot_len) || (p->next == 0));\n      if(p->type != PBUF_ROM) {\n        copy_needed = 1;\n        break;\n      }\n      p = p->next;\n    }\n    if(copy_needed) {\n      /* copy the whole packet into new pbufs */\n      p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\n      if(p != NULL) {\n        if (pbuf_copy(p, q) != ERR_OK) {\n          pbuf_free(p);\n          p = NULL;\n        }\n      }\n    } else {\n      /* referencing the old pbuf is enough */\n      p = q;\n      pbuf_ref(p);\n    }\n    /* packet could be taken over? */\n    if (p != NULL) {\n      /* queue packet ... */\n#if ARP_QUEUEING\n      struct etharp_q_entry *new_entry;\n      /* allocate a new arp queue entry */\n      new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);\n      if (new_entry != NULL) {\n    \tunsigned int qlen = 0;\n        new_entry->next = 0;\n        new_entry->p = p;\n        if(arp_table[i].q != NULL) {\n          /* queue was already existent, append the new entry to the end */\n          struct etharp_q_entry *r;\n          r = arp_table[i].q;\n          qlen++;\n          while (r->next != NULL) {\n            r = r->next;\n            qlen++;\n          }\n          r->next = new_entry;\n        } else {\n          /* queue did not exist, first item in queue */\n          arp_table[i].q = new_entry;\n        }\n        if(qlen >= 3) {\n        \tstruct etharp_q_entry *old;\n        \told = arp_table[i].q;\n        \tarp_table[i].q = arp_table[i].q->next;\n        \tpbuf_free(old->p);\n        \tmemp_free(MEM_ARP_QUEUE, old);\n        }\n        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_query: queued packet %p on ARP entry %\"S16_F\"\\n\", (void *)q, (s16_t)i));\n        result = ERR_OK;\n      } else {\n        /* the pool MEMP_ARP_QUEUE is empty */\n        pbuf_free(p);\n        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\\n\", (void *)q));\n        result = ERR_MEM;\n      }\n#else /* ARP_QUEUEING */\n      /* always queue one packet per ARP request only, freeing a previously queued packet */\n      if (arp_table[i].q != NULL) {\n        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_query: dropped previously queued packet %p for ARP entry %\"S16_F\"\\n\", (void *)q, (s16_t)i));\n        pbuf_free(arp_table[i].q);\n      }\n      arp_table[i].q = p;\n      result = ERR_OK;\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_query: queued packet %p on ARP entry %\"S16_F\"\\n\", (void *)q, (s16_t)i));\n#endif /* ARP_QUEUEING */\n    } else {\n      ETHARP_STATS_INC(etharp.memerr);\n      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\\n\", (void *)q));\n      result = ERR_MEM;\n    }\n  }\n  return result;\n}\n\n/**\n * Send a raw ARP packet (opcode and all addresses can be modified)\n *\n * @param netif the lwip network interface on which to send the ARP packet\n * @param ethsrc_addr the source MAC address for the ethernet header\n * @param ethdst_addr the destination MAC address for the ethernet header\n * @param hwsrc_addr the source MAC address for the ARP protocol header\n * @param ipsrc_addr the source IP address for the ARP protocol header\n * @param hwdst_addr the destination MAC address for the ARP protocol header\n * @param ipdst_addr the destination IP address for the ARP protocol header\n * @param opcode the type of the ARP packet\n * @return ERR_OK if the ARP packet has been sent\n *         ERR_MEM if the ARP packet couldn't be allocated\n *         any other err_t on failure\n */\n#if !LWIP_AUTOIP\nstatic\n#endif /* LWIP_AUTOIP */\nerr_t ICACHE_FLASH_ATTR\netharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,\n           const struct eth_addr *ethdst_addr,\n           const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,\n           const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,\n           const u16_t opcode)\n{\n  struct pbuf *p;\n  err_t result = ERR_OK;\n  struct eth_hdr *ethhdr;\n  struct etharp_hdr *hdr;\n#if LWIP_AUTOIP\n  const u8_t * ethdst_hwaddr;\n#endif /* LWIP_AUTOIP */\n\n  /* allocate a pbuf for the outgoing ARP request packet */\n  p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);\n  /* could allocate a pbuf for an ARP request? */\n  if (p == NULL) {\n    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,\n      (\"etharp_raw: could not allocate pbuf for ARP request.\\n\"));\n    ETHARP_STATS_INC(etharp.memerr);\n    return ERR_MEM;\n  }\n  LWIP_ASSERT(\"check that first pbuf can hold struct etharp_hdr\",\n              (p->len >= SIZEOF_ETHARP_PACKET));\n\n  ethhdr = (struct eth_hdr *)p->payload;\n  hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_raw: sending raw ARP packet.\\n\"));\n  hdr->opcode = htons(opcode);\n\n  LWIP_ASSERT(\"netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!\",\n              (netif->hwaddr_len == ETHARP_HWADDR_LEN));\n#if LWIP_AUTOIP\n  /* If we are using Link-Local, all ARP packets that contain a Link-Local\n   * 'sender IP address' MUST be sent using link-layer broadcast instead of\n   * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */\n  ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;\n#endif /* LWIP_AUTOIP */\n  /* Write the ARP MAC-Addresses */\n  ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);\n  ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);\n  /* Write the Ethernet MAC-Addresses */\n#if LWIP_AUTOIP\n  ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);\n#else  /* LWIP_AUTOIP */\n  ETHADDR16_COPY(&ethhdr->dest, ethdst_addr);\n#endif /* LWIP_AUTOIP */\n  ETHADDR16_COPY(&ethhdr->src, ethsrc_addr);\n  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without\n   * structure packing. */ \n  IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr);\n  IPADDR2_COPY(&hdr->dipaddr, ipdst_addr);\n\n  hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET);\n  hdr->proto = PP_HTONS(ETHTYPE_IP);\n  /* set hwlen and protolen */\n  hdr->hwlen = ETHARP_HWADDR_LEN;\n  hdr->protolen = sizeof(ip_addr_t);\n\n  ethhdr->type = PP_HTONS(ETHTYPE_ARP);\n  /* send ARP query */\n  result = netif->linkoutput(netif, p);\n  ETHARP_STATS_INC(etharp.xmit);\n  /* free ARP query packet */\n  pbuf_free(p);\n  p = NULL;\n  /* could not allocate pbuf for ARP request */\n\n  return result;\n}\n\n/**\n * Send an ARP request packet asking for ipaddr.\n *\n * @param netif the lwip network interface on which to send the request\n * @param ipaddr the IP address for which to ask\n * @return ERR_OK if the request has been sent\n *         ERR_MEM if the ARP packet couldn't be allocated\n *         any other err_t on failure\n */\nerr_t\netharp_request(struct netif *netif, ip_addr_t *ipaddr)\n{\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, (\"etharp_request: sending ARP request.\\n\"));\n  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,\n                    (struct eth_addr *)netif->hwaddr, &netif->ip_addr, &ethzero,\n                    ipaddr, ARP_REQUEST);\n}\n#endif /* LWIP_ARP */\n\n/**\n * Process received ethernet frames. Using this function instead of directly\n * calling ip_input and passing ARP frames through etharp in ethernetif_input,\n * the ARP cache is protected from concurrent access.\n *\n * @param p the recevied packet, p->payload pointing to the ethernet header\n * @param netif the network interface on which the packet was received\n */\nerr_t\nethernet_input(struct pbuf *p, struct netif *netif)\n{\n  struct eth_hdr* ethhdr;\n  u16_t type;\n  s16_t ip_hdr_offset = SIZEOF_ETH_HDR;\n\n  if (p->len <= SIZEOF_ETH_HDR) {\n    /* a packet with only an ethernet header (or less) is not valid for us modify by ives at 2014.4.24*/\n    ETHARP_STATS_INC(etharp.proterr);\n    ETHARP_STATS_INC(etharp.drop);\n    goto free_and_return;\n  }\n\n  /* points to packet payload, which starts with an Ethernet header */\n  ethhdr = (struct eth_hdr *)p->payload;\n  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,\n    (\"ethernet_input: dest:%\"X8_F\":%\"X8_F\":%\"X8_F\":%\"X8_F\":%\"X8_F\":%\"X8_F\", src:%\"X8_F\":%\"X8_F\":%\"X8_F\":%\"X8_F\":%\"X8_F\":%\"X8_F\", type:%\"X16_F\"\\n\",\n     (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2],\n     (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5],\n     (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2],\n     (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5],\n     (unsigned)htons(ethhdr->type)));\n\n  type = ethhdr->type;\n#if ETHARP_SUPPORT_VLAN\n  if (type == PP_HTONS(ETHTYPE_VLAN)) {\n    struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);\n    if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {\n      /* a packet with only an ethernet/vlan header (or less) is not valid for us modify by ives at 2014.4.24*/\n      ETHARP_STATS_INC(etharp.proterr);\n      ETHARP_STATS_INC(etharp.drop);\n      goto free_and_return;\n    }\n#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */\n    if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {\n      /* silently ignore this packet: not for our VLAN */\n      pbuf_free(p);\n      return ERR_OK;\n    }\n#endif /* ETHARP_VLAN_CHECK */\n    type = vlan->tpid;\n    ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;\n  }\n#endif /* ETHARP_SUPPORT_VLAN */\n\n#if LWIP_ARP_FILTER_NETIF\n  netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type));\n#endif /* LWIP_ARP_FILTER_NETIF*/\n\n  switch (type) {\n#if LWIP_ARP\n    /* IP packet? */\n    case PP_HTONS(ETHTYPE_IP):\n      if (!(netif->flags & NETIF_FLAG_ETHARP)) {\n        goto free_and_return;\n      }\n#if ETHARP_TRUST_IP_MAC\n      /* update ARP table */\n      etharp_ip_input(netif, p);\n#endif /* ETHARP_TRUST_IP_MAC */\n      /* skip Ethernet header */\n      if(pbuf_header(p, -ip_hdr_offset)) {\n        LWIP_ASSERT(\"Can't move over header in packet\", 0);\n        goto free_and_return;\n      } else {\n        /* pass to IP layer */\n        ip_input(p, netif);\n      }\n      break;\n      \n    case PP_HTONS(ETHTYPE_ARP):\n      if (!(netif->flags & NETIF_FLAG_ETHARP)) {\n        goto free_and_return;\n      }\n      /* pass p to ARP module */\n      etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);\n      break;\n#endif /* LWIP_ARP */\n#if PPPOE_SUPPORT\n    case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */\n      pppoe_disc_input(netif, p);\n      break;\n\n    case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */\n      pppoe_data_input(netif, p);\n      break;\n#endif /* PPPOE_SUPPORT */\n\n    default:\n      ETHARP_STATS_INC(etharp.proterr);\n      ETHARP_STATS_INC(etharp.drop);\n      goto free_and_return;\n  }\n\n  /* This means the pbuf is freed or consumed,\n     so the caller doesn't have to free it again */\n  return ERR_OK;\n\nfree_and_return:\n  pbuf_free(p);\n  return ERR_OK;\n}\n#endif /* LWIP_ARP || LWIP_ETHERNET */\n"
  },
  {
    "path": "app/mqtt/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = mqtt.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../libc\nINCLUDES += -I ../\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/mqtt/app.c",
    "content": "#include \"c_types.h\"\n#include \"c_string.h\"\n#include \"c_stdio.h\"\n#include \"user_interface.h\"\n#include \"mem.h\"\n#include \"osapi.h\"\n#include \"user_config.h\"\n#include \"espconn.h\"\n\n#include \"mqtt.h\"\n#include \"mqtt_msg.h\"\n\n#include \"driver/relay.h\"\n\n#include \"sensor/sensors.h\"\n\n#include \"serial_number.h\"\n\n#define MQTT_SERVER_IP \"104.131.71.110\"\n#define MQTT_RELAY_SET_SUFIX \"/SET\"\n\nstatic os_timer_t mqtt_timer;\nstatic MQTT_Client mqtt_client;\n\nstatic os_timer_t sensor_read_timer;\n\nstatic uint8_t wifiStatus = STATION_IDLE, lastWifiStatus = STATION_IDLE;\n\ntypedef struct mqtt_relay{\n\tuint8_t id;\n\tchar topic[20];\t\t\n}mqtt_relay;\n\nmqtt_relay relays[RELAY_COUNT];\n\nstatic void mqtt_relay_change_cb(int id,int state){\n\n\tMQTT_DBG(\"mqtt_relay_change_cb #%d %d\",id,state);\n\n\tmqtt_relay * relay = &relays[id];\t\n\n\tif(state<0)\n\t\tstate = relay_get_state(id);\n\n\tMQTT_Publish(&mqtt_client, relay->topic, state?\"1\":\"0\", 1, 0, 1);\n\n}\n\nstatic void ICACHE_FLASH_ATTR mqtt_app_timer_cb(void *arg){\n\n\t\n\tstruct ip_info ipConfig;\n\t\n\twifi_get_ip_info(STATION_IF, &ipConfig);\t\n\twifiStatus = wifi_station_get_connect_status();\n\n\t//check wifi\n\tif(wifiStatus != lastWifiStatus){\n\n\t\tlastWifiStatus = wifiStatus;\n\t\t\n\t\tif(wifiStatus==STATION_GOT_IP && ipConfig.ip.addr != 0){\n        \tMQTT_DBG(\"MQTT: Detected wifi network up\");\n        \tMQTT_Connect(&mqtt_client);       \n\t    }\n\t    else{\n\t    \tMQTT_DBG(\"MQTT: Detected wifi network down\");\n\t    \tMQTT_Disconnect(&mqtt_client);    \n\t    }\n\n\t}\n\t    \n}\n\n\n\nstatic void mqttConnectedCb(uint32_t *args)\n{\n\tMQTT_Client* client = (MQTT_Client*)args;\n\tMQTT_DBG(\"MQTT: Connected\");\n\n\tint i;\n\tfor(i=0;i<relay_count();i++){\n\n\t\tchar * setTopic = (char *)os_zalloc(strlen(relays[i].topic)+strlen(MQTT_RELAY_SET_SUFIX)+1);\n\t\tos_strcpy(setTopic,relays[i].topic);\n\t\tos_strcat(setTopic,MQTT_RELAY_SET_SUFIX);\n\n\t\tMQTT_Subscribe(client, setTopic, 1);\n\n\t\tos_free(setTopic);\n\n\t\tmqtt_relay_change_cb(i,-1); //force 1st publish\n\t}\n\t\n\t\n\n}\n\nstatic void mqttDisconnectedCb(uint32_t *args)\n{\n\tMQTT_Client* client = (MQTT_Client*)args;\n\tMQTT_DBG(\"MQTT: Disconnected\");\n}\n\nstatic void mqttPublishedCb(uint32_t *args)\n{\n\tMQTT_Client* client = (MQTT_Client*)args;\n\tMQTT_DBG(\"MQTT: Published\");\n}\n\nstatic void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len)\n{\n\tchar *topicBuf = (char*)os_zalloc(topic_len+1),\n\t\t\t*dataBuf = (char*)os_zalloc(data_len+1);\n\n\tMQTT_Client* client = (MQTT_Client*)args;\n\n\tos_memcpy(topicBuf, topic, topic_len);\n\ttopicBuf[topic_len] = 0;\n\n\tos_memcpy(dataBuf, data, data_len);\n\tdataBuf[data_len] = 0;\n\n\tMQTT_DBG(\"Receive topic: %s, data: %s \", topicBuf, dataBuf);\n\n\tos_free(topicBuf);\n\tos_free(dataBuf);\n\n\t// set relay\n\tint i;\n\tfor(i=0;i<relay_count();i++){\n\n\t\tmqtt_relay *r = &relays[i];\n\n\t\t//compare topic\n\t\tif(os_strncmp(topic,r->topic,strlen(r->topic))==0){\n\t\t\tMQTT_DBG(\"Topic 1st part match\");\n\t\t\t//check set suffix\n\t\t\tif(os_strncmp(topic+strlen(r->topic),MQTT_RELAY_SET_SUFIX,strlen(MQTT_RELAY_SET_SUFIX))==0)\n\t\t\t{\n\t\t\t\tMQTT_DBG(\"Topic 2nd part match\");\n\t\t\t\tint state = data[0] - '0';\n\n\t\t\t\tif(state==0 || state == 1)\n\t\t\t\t{\n\t\t\t\t\tMQTT_DBG(\"Setting relay #%d to %d via MQTT\", i, state);\n\t\t\t\t\trelay_set_state(i,state);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t\n\t\t\t}\n\t\t} \n\t\t\t\n\n\t}\n\n\t\n}\n\nstatic void ICACHE_FLASH_ATTR sensor_read_timer_cb(void *arg){\n\n\tchar * buff = (char *)os_zalloc(64);\n\n\tsensor_data data;\n\tsensors_get_data(&data);\t\n\n\tc_sprintf(buff,\"%f\",data.dht22.temp);\n\tMQTT_Publish(&mqtt_client, \"temperature/\"SERIAL_NUMBER, buff, strlen(buff), 0, 1);\n\n\tos_memset(buff,0,64);\n\tc_sprintf(buff,\"%f\",data.dht22.hum);\n\tMQTT_Publish(&mqtt_client, \"humidity/\"SERIAL_NUMBER, buff, strlen(buff), 0, 1);\n\n\tos_memset(buff,0,64);\n\tc_sprintf(buff,\"%d\",data.bmp180.press);\n\tMQTT_Publish(&mqtt_client, \"pressure/\"SERIAL_NUMBER, buff, strlen(buff), 0, 1);\n\n\tos_free(buff);\n\n\n\n}\n\nvoid ICACHE_FLASH_ATTR mqtt_app_init(){\n\t\n\n\t//set relays\n\tint i;\n\tfor(i=0;i<relay_count();i++){\n\t\trelays[i].id=i;\t\t\n\t\tos_strcpy(relays[i].topic,\"relay/\");\n\t\tos_strcat(relays[i].topic,SERIAL_NUMBER\"/\");\n\t\tos_strcati(relays[i].topic,i);\n\t}\n\n\t//register listeners \n\trelay_register_listener(mqtt_relay_change_cb);\n\n\tMQTT_InitConnection(&mqtt_client, MQTT_SERVER_IP, 1883, 0);\n\tMQTT_InitClient(&mqtt_client, SERIAL_NUMBER, NULL, NULL, 120, 1);\n\n\tMQTT_OnConnected(&mqtt_client, mqttConnectedCb);\n\tMQTT_OnDisconnected(&mqtt_client, mqttDisconnectedCb);\n\tMQTT_OnPublished(&mqtt_client, mqttPublishedCb);\n\tMQTT_OnData(&mqtt_client, mqttDataCb);\n\t\n\t//arm mqtt timer\n\tos_memset(&mqtt_timer,0,sizeof(os_timer_t));\n\tos_timer_disarm(&mqtt_timer);\n\tos_timer_setfn(&mqtt_timer, (os_timer_func_t *)mqtt_app_timer_cb, NULL);\n\tos_timer_arm(&mqtt_timer, 2000, 1);\n\n\t//arm sensor read timer\n\tos_memset(&sensor_read_timer,0,sizeof(os_timer_t));\n\tos_timer_disarm(&sensor_read_timer);\n\tos_timer_setfn(&sensor_read_timer, (os_timer_func_t *)sensor_read_timer_cb, NULL);\n\tos_timer_arm(&sensor_read_timer, 5000, 1);\n\n}"
  },
  {
    "path": "app/mqtt/app.h",
    "content": "#ifndef __MQTT_APP_H\n#define __MQTT_APP_H\n\nvoid ICACHE_FLASH_ATTR mqtt_app_init();\n\n#endif"
  },
  {
    "path": "app/mqtt/mqtt.c",
    "content": "/* mqtt.c\n*  Protocol: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html\n*\n* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions are met:\n*\n* * Redistributions of source code must retain the above copyright notice,\n* this list of conditions and the following disclaimer.\n* * Redistributions in binary form must reproduce the above copyright\n* notice, this list of conditions and the following disclaimer in the\n* documentation and/or other materials provided with the distribution.\n* * Neither the name of Redis nor the names of its contributors may be used\n* to endorse or promote products derived from this software without\n* specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n* POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include \"user_interface.h\"\n#include \"osapi.h\"\n#include \"espconn.h\"\n#include \"os_type.h\"\n#include \"mem.h\"\n#include \"mqtt_msg.h\"\n#include \"user_config.h\"\n#include \"mqtt.h\"\n#include \"queue.h\"\n\n#define MQTT_TASK_PRIO        \t\t0\n#define MQTT_TASK_QUEUE_SIZE    \t1\n#define MQTT_SEND_TIMOUT\t\t\t5\n\nunsigned char *default_certificate;\nunsigned int default_certificate_len = 0;\nunsigned char *default_private_key;\nunsigned int default_private_key_len = 0;\n\nos_event_t mqtt_procTaskQueue[MQTT_TASK_QUEUE_SIZE];\n\nLOCAL void ICACHE_FLASH_ATTR\nmqtt_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)\n{\n\tstruct espconn *pConn = (struct espconn *)arg;\n\tMQTT_Client* client = (MQTT_Client *)pConn->reverse;\n\n\n\tif(ipaddr == NULL)\n\t{\n\t\tMQTT_DBG(\"DNS: Found, but got no ip, try to reconnect\");\n\t\tclient->connState = TCP_RECONNECT_REQ;\n\t\treturn;\n\t}\n\n\tMQTT_DBG(\"DNS: found ip %d.%d.%d.%d\",\n\t\t\t*((uint8 *) &ipaddr->addr),\n\t\t\t*((uint8 *) &ipaddr->addr + 1),\n\t\t\t*((uint8 *) &ipaddr->addr + 2),\n\t\t\t*((uint8 *) &ipaddr->addr + 3));\n\n\tif(client->ip.addr == 0 && ipaddr->addr != 0)\n\t{\n\t\tos_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);\n\t\tif(client->security){\n\t\t\tespconn_secure_connect(client->pCon);\n\t\t}\n\t\telse {\n\t\t\tespconn_connect(client->pCon);\n\t\t}\n\n\t\tclient->connState = TCP_CONNECTING;\n\t\tMQTT_DBG(\"TCP: connecting...\");\n\t}\n\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n}\n\n\n\nLOCAL void ICACHE_FLASH_ATTR\ndeliver_publish(MQTT_Client* client, uint8_t* message, int length)\n{\n\tmqtt_event_data_t event_data;\n\n\tevent_data.topic_length = length;\n\tevent_data.topic = mqtt_get_publish_topic(message, &event_data.topic_length);\n\tevent_data.data_length = length;\n\tevent_data.data = mqtt_get_publish_data(message, &event_data.data_length);\n\n\tif(client->dataCb)\n\t\tclient->dataCb((uint32_t*)client, event_data.topic, event_data.topic_length, event_data.data, event_data.data_length);\n\n}\n\n\n/**\n  * @brief  Client received callback function.\n  * @param  arg: contain the ip link information\n  * @param  pdata: received data\n  * @param  len: the lenght of received data\n  * @retval None\n  */\nvoid ICACHE_FLASH_ATTR\nmqtt_tcpclient_recv(void *arg, char *pdata, unsigned short len)\n{\n\tuint8_t msg_type;\n\tuint8_t msg_qos;\n\tuint16_t msg_id;\n\n\tstruct espconn *pCon = (struct espconn*)arg;\n\tMQTT_Client *client = (MQTT_Client *)pCon->reverse;\n\nREADPACKET:\n\tMQTT_DBG(\"TCP: data received %d bytes\", len);\n\tif(len < MQTT_BUF_SIZE && len > 0){\n\t\tos_memcpy(client->mqtt_state.in_buffer, pdata, len);\n\n\t\tmsg_type = mqtt_get_type(client->mqtt_state.in_buffer);\n\t\tmsg_qos = mqtt_get_qos(client->mqtt_state.in_buffer);\n\t\tmsg_id = mqtt_get_id(client->mqtt_state.in_buffer, client->mqtt_state.in_buffer_length);\n\t\tswitch(client->connState){\n\t\tcase MQTT_CONNECT_SENDING:\n\t\t\tif(msg_type == MQTT_MSG_TYPE_CONNACK){\n\t\t\t\tif(client->mqtt_state.pending_msg_type != MQTT_MSG_TYPE_CONNECT){\n\t\t\t\t\tMQTT_DBG(\"MQTT: Invalid packet\");\n\t\t\t\t\tif(client->security){\n\t\t\t\t\t\tespconn_secure_disconnect(client->pCon);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tespconn_disconnect(client->pCon);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tMQTT_DBG(\"MQTT: Connected to %s:%d\", client->host, client->port);\n\t\t\t\t\tclient->connState = MQTT_DATA;\n\t\t\t\t\tif(client->connectedCb)\n\t\t\t\t\t\tclient->connectedCb((uint32_t*)client);\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tbreak;\n\t\tcase MQTT_DATA:\n\t\t\tclient->mqtt_state.message_length_read = len;\n\t\t\tclient->mqtt_state.message_length = mqtt_get_total_length(client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);\n\n\n\t\t\tswitch(msg_type)\n\t\t\t{\n\n\t\t\t  case MQTT_MSG_TYPE_SUBACK:\n\t\t\t\tif(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)\n\t\t\t\t  MQTT_DBG(\"MQTT: Subscribe successful\");\n\t\t\t\tbreak;\n\t\t\t  case MQTT_MSG_TYPE_UNSUBACK:\n\t\t\t\tif(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && client->mqtt_state.pending_msg_id == msg_id)\n\t\t\t\t  MQTT_DBG(\"MQTT: UnSubscribe successful\");\n\t\t\t\tbreak;\n\t\t\t  case MQTT_MSG_TYPE_PUBLISH:\n\t\t\t\tif(msg_qos == 1)\n\t\t\t\t\tclient->mqtt_state.outbound_message = mqtt_msg_puback(&client->mqtt_state.mqtt_connection, msg_id);\n\t\t\t\telse if(msg_qos == 2)\n\t\t\t\t\tclient->mqtt_state.outbound_message = mqtt_msg_pubrec(&client->mqtt_state.mqtt_connection, msg_id);\n\t\t\t\tif(msg_qos == 1 || msg_qos == 2){\n\t\t\t\t\tMQTT_DBG(\"MQTT: Queue response QoS: %d\", msg_qos);\n\t\t\t\t\tif(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){\n\t\t\t\t\t\tMQTT_DBG(\"MQTT: Queue full\");\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tdeliver_publish(client, client->mqtt_state.in_buffer, client->mqtt_state.message_length_read);\n\t\t\t\tbreak;\n\t\t\t  case MQTT_MSG_TYPE_PUBACK:\n\t\t\t\tif(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){\n\t\t\t\t  MQTT_DBG(\"MQTT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish\");\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t  case MQTT_MSG_TYPE_PUBREC:\n\t\t\t\t  client->mqtt_state.outbound_message = mqtt_msg_pubrel(&client->mqtt_state.mqtt_connection, msg_id);\n\t\t\t\t  if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){\n\t\t\t\t  \tMQTT_DBG(\"MQTT: Queue full\");\n\t\t\t\t  }\n\t\t\t\tbreak;\n\t\t\t  case MQTT_MSG_TYPE_PUBREL:\n\t\t\t\t  client->mqtt_state.outbound_message = mqtt_msg_pubcomp(&client->mqtt_state.mqtt_connection, msg_id);\n\t\t\t\t  if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){\n\t\t\t\t\tMQTT_DBG(\"MQTT: Queue full\");\n\t\t\t\t  }\n\t\t\t\tbreak;\n\t\t\t  case MQTT_MSG_TYPE_PUBCOMP:\n\t\t\t\tif(client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH && client->mqtt_state.pending_msg_id == msg_id){\n\t\t\t\t  MQTT_DBG(\"MQTT: receive MQTT_MSG_TYPE_PUBCOMP, finish QoS2 publish\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t  case MQTT_MSG_TYPE_PINGREQ:\n\t\t\t\t  client->mqtt_state.outbound_message = mqtt_msg_pingresp(&client->mqtt_state.mqtt_connection);\n\t\t\t\t  if(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){\n\t\t\t\t\tMQTT_DBG(\"MQTT: Queue full\");\n\t\t\t\t  }\n\t\t\t\tbreak;\n\t\t\t  case MQTT_MSG_TYPE_PINGRESP:\n\t\t\t\t// Ignore\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// NOTE: this is done down here and not in the switch case above\n\t\t\t// because the PSOCK_READBUF_LEN() won't work inside a switch\n\t\t\t// statement due to the way protothreads resume.\n\t\t\tif(msg_type == MQTT_MSG_TYPE_PUBLISH)\n\t\t\t{\n\t\t\t  len = client->mqtt_state.message_length_read;\n\n\t\t\t  if(client->mqtt_state.message_length < client->mqtt_state.message_length_read)\n\t\t\t  {\n\t\t\t\t  //client->connState = MQTT_PUBLISH_RECV;\n\t\t\t\t  //Not Implement yet\n\t\t\t\t  len -= client->mqtt_state.message_length;\n\t\t\t\t  pdata += client->mqtt_state.message_length;\n\n\t\t\t\t  MQTT_DBG(\"Get another published message\");\n\t\t\t\t  goto READPACKET;\n\t\t\t  }\n\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t} else {\n\t\tMQTT_DBG(\"ERROR: Message too long\");\n\t}\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n}\n\n/**\n  * @brief  Client send over callback function.\n  * @param  arg: contain the ip link information\n  * @retval None\n  */\nvoid ICACHE_FLASH_ATTR\nmqtt_tcpclient_sent_cb(void *arg)\n{\n\tstruct espconn *pCon = (struct espconn *)arg;\n\tMQTT_Client* client = (MQTT_Client *)pCon->reverse;\n\tMQTT_DBG(\"TCP: Sent\");\n\tclient->sendTimeout = 0;\n\tif(client->connState == MQTT_DATA && client->mqtt_state.pending_msg_type == MQTT_MSG_TYPE_PUBLISH){\n\t\tif(client->publishedCb)\n\t\t\tclient->publishedCb((uint32_t*)client);\n\t}\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n}\n\nvoid ICACHE_FLASH_ATTR mqtt_timer(void *arg)\n{\n\tMQTT_Client* client = (MQTT_Client*)arg;\n\n\tif(client->connState == MQTT_DATA){\n\t\tclient->keepAliveTick ++;\n\t\tif(client->keepAliveTick > client->mqtt_state.connect_info->keepalive){\n\n\t\t\tMQTT_DBG(\"MQTT: Send keepalive packet to %s:%d!\", client->host, client->port);\n\t\t\tclient->mqtt_state.outbound_message = mqtt_msg_pingreq(&client->mqtt_state.mqtt_connection);\n\t\t\tclient->mqtt_state.pending_msg_type = MQTT_MSG_TYPE_PINGREQ;\n\t\t\tclient->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);\n\t\t\tclient->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);\n\n\n\t\t\tclient->sendTimeout = MQTT_SEND_TIMOUT;\n\t\t\tMQTT_DBG(\"MQTT: Sending, type: %d, id: %04X\",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);\n\t\t\tif(client->security){\n\t\t\t\tespconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tespconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);\n\t\t\t}\n\n\t\t\tclient->mqtt_state.outbound_message = NULL;\n\n\t\t\tclient->keepAliveTick = 0;\n\t\t\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n\t\t}\n\n\t} else if(client->connState == TCP_RECONNECT_REQ){\n\t\tclient->reconnectTick ++;\n\t\tif(client->reconnectTick > MQTT_RECONNECT_TIMEOUT) {\n\t\t\tclient->reconnectTick = 0;\n\t\t\tclient->connState = TCP_RECONNECT;\n\t\t\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n\t\t}\n\t}\n\tif(client->sendTimeout > 0)\n\t\tclient->sendTimeout --;\n}\n\nvoid ICACHE_FLASH_ATTR\nmqtt_tcpclient_discon_cb(void *arg)\n{\n\n\tstruct espconn *pespconn = (struct espconn *)arg;\n\tMQTT_Client* client = (MQTT_Client *)pespconn->reverse;\n\tMQTT_DBG(\"TCP: Disconnected callback\");\n\tclient->connState = TCP_RECONNECT_REQ;\n\tif(client->disconnectedCb)\n\t\tclient->disconnectedCb((uint32_t*)client);\n\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n}\n\n\n\n/**\n  * @brief  Tcp client connect success callback function.\n  * @param  arg: contain the ip link information\n  * @retval None\n  */\nvoid ICACHE_FLASH_ATTR\nmqtt_tcpclient_connect_cb(void *arg)\n{\n\n\n\tstruct espconn *pCon = (struct espconn *)arg;\n\tMQTT_Client* client = (MQTT_Client *)pCon->reverse;\n\n\t//set opt\n\tespconn_set_opt(pCon, ESPCONN_NODELAY | ESPCONN_REUSEADDR | ESPCONN_KEEPALIVE);\n\n\tespconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb);\n\tespconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);////////\n\tespconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb);///////\n\tMQTT_DBG(\"MQTT: Connected to broker %s:%d\", client->host, client->port);\n\n\tmqtt_msg_init(&client->mqtt_state.mqtt_connection, client->mqtt_state.out_buffer, client->mqtt_state.out_buffer_length);\n\tclient->mqtt_state.outbound_message = mqtt_msg_connect(&client->mqtt_state.mqtt_connection, client->mqtt_state.connect_info);\n\tclient->mqtt_state.pending_msg_type = mqtt_get_type(client->mqtt_state.outbound_message->data);\n\tclient->mqtt_state.pending_msg_id = mqtt_get_id(client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);\n\n\n\tclient->sendTimeout = MQTT_SEND_TIMOUT;\n\tMQTT_DBG(\"MQTT: Sending, type: %d, id: %04X\",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);\n\tif(client->security){\n\t\tespconn_secure_sent(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);\n\t}\n\telse{\n\t\tespconn_send(client->pCon, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length);\n\t}\n\n\tclient->mqtt_state.outbound_message = NULL;\n\tclient->connState = MQTT_CONNECT_SENDING;\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n}\n\n/**\n  * @brief  Tcp client connect repeat callback function.\n  * @param  arg: contain the ip link information\n  * @retval None\n  */\nvoid ICACHE_FLASH_ATTR\nmqtt_tcpclient_recon_cb(void *arg, sint8 errType)\n{\n\tstruct espconn *pCon = (struct espconn *)arg;\n\tMQTT_Client* client = (MQTT_Client *)pCon->reverse;\n\n\tMQTT_DBG(\"TCP: Reconnect to %s:%d\", client->host, client->port);\n\n\tclient->connState = TCP_RECONNECT_REQ;\n\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n\n}\n\n/**\n  * @brief  MQTT publish function.\n  * @param  client: \tMQTT_Client reference\n  * @param  topic: \t\tstring topic will publish to\n  * @param  data: \t\tbuffer data send point to\n  * @param  data_length: length of data\n  * @param  qos:\t\tqos\n  * @param  retain:\t\tretain\n  * @retval TRUE if success queue\n  */\nBOOL ICACHE_FLASH_ATTR\nMQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain)\n{\n\tuint8_t dataBuffer[MQTT_BUF_SIZE];\n\tuint16_t dataLen;\n\tclient->mqtt_state.outbound_message = mqtt_msg_publish(&client->mqtt_state.mqtt_connection,\n\t\t\t\t\t\t\t\t\t\t topic, data, data_length,\n\t\t\t\t\t\t\t\t\t\t qos, retain,\n\t\t\t\t\t\t\t\t\t\t &client->mqtt_state.pending_msg_id);\n\tif(client->mqtt_state.outbound_message->length == 0){\n\t\tMQTT_DBG(\"MQTT: Queuing publish failed\");\n\t\treturn FALSE;\n\t}\n\tMQTT_DBG(\"MQTT: queuing publish, length: %d, queue size(%d/%d)\", client->mqtt_state.outbound_message->length, client->msgQueue.rb.fill_cnt, client->msgQueue.rb.size);\n\twhile(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){\n\t\tMQTT_DBG(\"MQTT: Queue full\");\n\t\tif(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {\n\t\t\tMQTT_DBG(\"MQTT: Serious buffer error\");\n\t\t\treturn FALSE;\n\t\t}\n\t}\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n\treturn TRUE;\n}\n\n/**\n  * @brief  MQTT subscibe function.\n  * @param  client: \tMQTT_Client reference\n  * @param  topic: \t\tstring topic will subscribe\n  * @param  qos:\t\tqos\n  * @retval TRUE if success queue\n  */\nBOOL ICACHE_FLASH_ATTR\nMQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos)\n{\n\tuint8_t dataBuffer[MQTT_BUF_SIZE];\n\tuint16_t dataLen;\n\n\tclient->mqtt_state.outbound_message = mqtt_msg_subscribe(&client->mqtt_state.mqtt_connection,\n\t\t\t\t\t\t\t\t\t\t\ttopic, 0,\n\t\t\t\t\t\t\t\t\t\t\t&client->mqtt_state.pending_msg_id);\n\tMQTT_DBG(\"MQTT: queue subscribe, topic\\\"%s\\\", id: %d\",topic, client->mqtt_state.pending_msg_id);\n\twhile(QUEUE_Puts(&client->msgQueue, client->mqtt_state.outbound_message->data, client->mqtt_state.outbound_message->length) == -1){\n\t\tMQTT_DBG(\"MQTT: Queue full\");\n\t\tif(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == -1) {\n\t\t\tMQTT_DBG(\"MQTT: Serious buffer error\");\n\t\t\treturn FALSE;\n\t\t}\n\t}\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)client);\n\treturn TRUE;\n}\n\nvoid ICACHE_FLASH_ATTR\nMQTT_Task(os_event_t *e)\n{\n\tMQTT_Client* client = (MQTT_Client*)e->par;\n\tuint8_t dataBuffer[MQTT_BUF_SIZE];\n\tuint16_t dataLen;\n\tif(e->par == 0)\n\t\treturn;\n\tswitch(client->connState){\n\n\tcase TCP_RECONNECT_REQ:\n\t\tbreak;\n\tcase TCP_RECONNECT:\n\t\tMQTT_Connect(client);\n\t\tMQTT_DBG(\"TCP: Reconnect to: %s:%d\", client->host, client->port);\n\t\tclient->connState = TCP_CONNECTING;\n\t\tbreak;\n\tcase MQTT_DATA:\n\t\tif(QUEUE_IsEmpty(&client->msgQueue) || client->sendTimeout != 0) {\n\t\t\tbreak;\n\t\t}\n\t\tif(QUEUE_Gets(&client->msgQueue, dataBuffer, &dataLen, MQTT_BUF_SIZE) == 0){\n\t\t\tclient->mqtt_state.pending_msg_type = mqtt_get_type(dataBuffer);\n\t\t\tclient->mqtt_state.pending_msg_id = mqtt_get_id(dataBuffer, dataLen);\n\n\n\t\t\tclient->sendTimeout = MQTT_SEND_TIMOUT;\n\t\t\tMQTT_DBG(\"MQTT: Sending, type: %d, id: %04X\",client->mqtt_state.pending_msg_type, client->mqtt_state.pending_msg_id);\n\t\t\tif(client->security){\n\t\t\t\tespconn_secure_sent(client->pCon, dataBuffer, dataLen);\n\t\t\t}\n\t\t\telse{\n\t\t\t\tespconn_send(client->pCon, dataBuffer, dataLen);\n\t\t\t}\n\n\t\t\tclient->mqtt_state.outbound_message = NULL;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\t}\n}\n\n/**\n  * @brief  MQTT initialization connection function\n  * @param  client: \tMQTT_Client reference\n  * @param  host: \tDomain or IP string\n  * @param  port: \tPort to connect\n  * @param  security:\t\t1 for ssl, 0 for none\n  * @retval None\n  */\nvoid ICACHE_FLASH_ATTR\nMQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security)\n{\n\tuint32_t temp;\n\tMQTT_DBG(\"MQTT_InitConnection\");\n\tos_memset(mqttClient, 0, sizeof(MQTT_Client));\n\ttemp = os_strlen(host);\n\tmqttClient->host = (uint8_t*)os_zalloc(temp + 1);\n\tos_strcpy(mqttClient->host, host);\n\tmqttClient->host[temp] = 0;\n\tmqttClient->port = port;\n\tmqttClient->security = security;\n\n}\n\n/**\n  * @brief  MQTT initialization mqtt client function\n  * @param  client: \tMQTT_Client reference\n  * @param  clientid: \tMQTT client id\n  * @param  client_user:MQTT client user\n  * @param  client_pass:MQTT client password\n  * @param  client_pass:MQTT keep alive timer, in second\n  * @retval None\n  */\nvoid ICACHE_FLASH_ATTR\nMQTT_InitClient(MQTT_Client *mqttClient, char* client_id, char* client_user, char* client_pass, uint32_t keepAliveTime, uint8_t cleanSession)\n{\n\tuint32_t temp;\n\tMQTT_DBG(\"MQTT_InitClient\");\n\n\tos_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t));\n\n\n\tmqttClient->connect_info.client_id= client_id;\n\n\tmqttClient->connect_info.username = client_user;\n\n\tmqttClient->connect_info.password = client_pass;\t\n\n\tmqttClient->connect_info.keepalive = keepAliveTime;\n\tmqttClient->connect_info.clean_session = cleanSession;\n\n\tmqttClient->mqtt_state.in_buffer = (uint8_t *)os_zalloc(MQTT_BUF_SIZE);\n\tmqttClient->mqtt_state.in_buffer_length = MQTT_BUF_SIZE;\n\tmqttClient->mqtt_state.out_buffer =  (uint8_t *)os_zalloc(MQTT_BUF_SIZE);\n\tmqttClient->mqtt_state.out_buffer_length = MQTT_BUF_SIZE;\n\tmqttClient->mqtt_state.connect_info = &mqttClient->connect_info;\n\n\tmqtt_msg_init(&mqttClient->mqtt_state.mqtt_connection, mqttClient->mqtt_state.out_buffer, mqttClient->mqtt_state.out_buffer_length);\n\n\tQUEUE_Init(&mqttClient->msgQueue, QUEUE_BUFFER_SIZE);\n\n\tsystem_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE);\n\tsystem_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient);\n}\nvoid ICACHE_FLASH_ATTR\nMQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain)\n{\n\tuint32_t temp;\n\ttemp = os_strlen(will_topic);\n\tmqttClient->connect_info.will_topic = (uint8_t*)os_zalloc(temp + 1);\n\tos_strcpy(mqttClient->connect_info.will_topic, will_topic);\n\tmqttClient->connect_info.will_topic[temp] = 0;\n\n\ttemp = os_strlen(will_msg);\n\tmqttClient->connect_info.will_message = (uint8_t*)os_zalloc(temp + 1);\n\tos_strcpy(mqttClient->connect_info.will_message, will_msg);\n\tmqttClient->connect_info.will_message[temp] = 0;\n\n\n\tmqttClient->connect_info.will_qos = will_qos;\n\tmqttClient->connect_info.will_retain = will_retain;\n}\n/**\n  * @brief  Begin connect to MQTT broker\n  * @param  client: MQTT_Client reference\n  * @retval None\n  */\nvoid ICACHE_FLASH_ATTR\nMQTT_Connect(MQTT_Client *mqttClient)\n{\n\tMQTT_Disconnect(mqttClient);\n\tmqttClient->pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));\n\tmqttClient->pCon->type = ESPCONN_TCP;\n\tmqttClient->pCon->state = ESPCONN_NONE;\n\tmqttClient->pCon->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));\n\tmqttClient->pCon->proto.tcp->local_port = espconn_port();\n\tmqttClient->pCon->proto.tcp->remote_port = mqttClient->port;\n\tmqttClient->pCon->reverse = mqttClient;\n\tespconn_regist_connectcb(mqttClient->pCon, mqtt_tcpclient_connect_cb);\n\tespconn_regist_reconcb(mqttClient->pCon, mqtt_tcpclient_recon_cb);\n\n\tmqttClient->keepAliveTick = 0;\n\tmqttClient->reconnectTick = 0;\n\n\n\tos_timer_disarm(&mqttClient->mqttTimer);\n\tos_timer_setfn(&mqttClient->mqttTimer, (os_timer_func_t *)mqtt_timer, mqttClient);\n\tos_timer_arm(&mqttClient->mqttTimer, 1000, 1);\n\n\tif(UTILS_StrToIP(mqttClient->host, &mqttClient->pCon->proto.tcp->remote_ip)) {\n\t\tMQTT_DBG(\"TCP: Connect to ip  %s:%d\", mqttClient->host, mqttClient->port);\n\t\tif(mqttClient->security){\n\t\t\tespconn_secure_connect(mqttClient->pCon);\n\t\t}\n\t\telse {\n\t\t\tespconn_connect(mqttClient->pCon);\n\t\t}\n\t}\n\telse {\n\t\tMQTT_DBG(\"TCP: Connect to domain %s:%d\", mqttClient->host, mqttClient->port);\n\t\tespconn_gethostbyname(mqttClient->pCon, mqttClient->host, &mqttClient->ip, mqtt_dns_found);\n\t}\n\tmqttClient->connState = TCP_CONNECTING;\n}\n\nvoid ICACHE_FLASH_ATTR\nMQTT_Disconnect(MQTT_Client *mqttClient)\n{\n\tif(mqttClient->pCon){\n\t\tMQTT_DBG(\"Free memory\");\n\t\tif(mqttClient->pCon->proto.tcp)\n\t\t\tos_free(mqttClient->pCon->proto.tcp);\n\t\tos_free(mqttClient->pCon);\n\t\tmqttClient->pCon = NULL;\n\t}\n\n\tos_timer_disarm(&mqttClient->mqttTimer);\n}\nvoid ICACHE_FLASH_ATTR\nMQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb)\n{\n\tmqttClient->connectedCb = connectedCb;\n}\n\nvoid ICACHE_FLASH_ATTR\nMQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb)\n{\n\tmqttClient->disconnectedCb = disconnectedCb;\n}\n\nvoid ICACHE_FLASH_ATTR\nMQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb)\n{\n\tmqttClient->dataCb = dataCb;\n}\n\nvoid ICACHE_FLASH_ATTR\nMQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb)\n{\n\tmqttClient->publishedCb = publishedCb;\n}\n"
  },
  {
    "path": "app/mqtt/mqtt.h",
    "content": "/* mqtt.h\n*\n* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions are met:\n*\n* * Redistributions of source code must retain the above copyright notice,\n* this list of conditions and the following disclaimer.\n* * Redistributions in binary form must reproduce the above copyright\n* notice, this list of conditions and the following disclaimer in the\n* documentation and/or other materials provided with the distribution.\n* * Neither the name of Redis nor the names of its contributors may be used\n* to endorse or promote products derived from this software without\n* specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n* POSSIBILITY OF SUCH DAMAGE.\n*/\n#ifndef USER_AT_MQTT_H_\n#define USER_AT_MQTT_H_\n#include \"mqtt_msg.h\"\n#include \"user_interface.h\"\n\n\n#define MQTT_BUF_SIZE   1024\n#define MQTT_RECONNECT_TIMEOUT  5\n#define QUEUE_BUFFER_SIZE       2048\n\n#define MQTT_DEBUG_ON\n\n#ifdef MQTT_DEBUG_ON\n#define MQTT_DBG NODE_DBG\n#else \n#define MQTT_DBG \n#endif\n\n#include \"queue.h\"\ntypedef struct mqtt_event_data_t\n{\n  uint8_t type;\n  const char* topic;\n  const char* data;\n  uint16_t topic_length;\n  uint16_t data_length;\n  uint16_t data_offset;\n} mqtt_event_data_t;\n\ntypedef struct mqtt_state_t\n{\n  uint16_t port;\n  int auto_reconnect;\n  mqtt_connect_info_t* connect_info;\n  uint8_t* in_buffer;\n  uint8_t* out_buffer;\n  int in_buffer_length;\n  int out_buffer_length;\n  uint16_t message_length;\n  uint16_t message_length_read;\n  mqtt_message_t* outbound_message;\n  mqtt_connection_t mqtt_connection;\n  uint16_t pending_msg_id;\n  int pending_msg_type;\n  int pending_publish_qos;\n} mqtt_state_t;\n\ntypedef enum {\n\tWIFI_INIT,\n\tWIFI_CONNECTING,\n\tWIFI_CONNECTING_ERROR,\n\tWIFI_CONNECTED,\n\tDNS_RESOLVE,\n\tTCP_DISCONNECTED,\n\tTCP_RECONNECT_REQ,\n\tTCP_RECONNECT,\n\tTCP_CONNECTING,\n\tTCP_CONNECTING_ERROR,\n\tTCP_CONNECTED,\n\tMQTT_CONNECT_SEND,\n\tMQTT_CONNECT_SENDING,\n\tMQTT_SUBSCIBE_SEND,\n\tMQTT_SUBSCIBE_SENDING,\n\tMQTT_DATA,\n\tMQTT_PUBLISH_RECV,\n\tMQTT_PUBLISHING\n} tConnState;\n\ntypedef void (*MqttCallback)(uint32_t *args);\ntypedef void (*MqttDataCallback)(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t lengh);\n\ntypedef struct  {\n\tstruct espconn *pCon;\n\tuint8_t security;\n\tuint8_t* host;\n\tuint32_t port;\n\tip_addr_t ip;\n\tmqtt_state_t  mqtt_state;\n\tmqtt_connect_info_t connect_info;\n\tMqttCallback connectedCb;\n\tMqttCallback disconnectedCb;\n\tMqttCallback publishedCb;\n\tMqttDataCallback dataCb;\n\tETSTimer mqttTimer;\n\tuint32_t keepAliveTick;\n\tuint32_t reconnectTick;\n\tuint32_t sendTimeout;\n\ttConnState connState;\n\tQUEUE msgQueue;\n\tvoid* user_data;\n} MQTT_Client;\n\n#define SEC_NONSSL 0\n#define SEC_SSL\t1\n\n#define MQTT_FLAG_CONNECTED \t1\n#define MQTT_FLAG_READY \t\t2\n#define MQTT_FLAG_EXIT \t\t\t4\n\n#define MQTT_EVENT_TYPE_NONE \t\t\t0\n#define MQTT_EVENT_TYPE_CONNECTED \t\t1\n#define MQTT_EVENT_TYPE_DISCONNECTED \t2\n#define MQTT_EVENT_TYPE_SUBSCRIBED \t\t3\n#define MQTT_EVENT_TYPE_UNSUBSCRIBED \t4\n#define MQTT_EVENT_TYPE_PUBLISH \t\t5\n#define MQTT_EVENT_TYPE_PUBLISHED \t\t6\n#define MQTT_EVENT_TYPE_EXITED \t\t\t7\n#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8\n\nvoid ICACHE_FLASH_ATTR MQTT_InitConnection(MQTT_Client *mqttClient, uint8_t* host, uint32 port, uint8_t security);\nvoid ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client *mqttClient, char* client_id, char* client_user, char* client_pass, uint32_t keepAliveTime, uint8_t cleanSession);\nvoid ICACHE_FLASH_ATTR MQTT_InitLWT(MQTT_Client *mqttClient, uint8_t* will_topic, uint8_t* will_msg, uint8_t will_qos, uint8_t will_retain);\nvoid ICACHE_FLASH_ATTR MQTT_OnConnected(MQTT_Client *mqttClient, MqttCallback connectedCb);\nvoid ICACHE_FLASH_ATTR MQTT_OnDisconnected(MQTT_Client *mqttClient, MqttCallback disconnectedCb);\nvoid ICACHE_FLASH_ATTR MQTT_OnPublished(MQTT_Client *mqttClient, MqttCallback publishedCb);\nvoid ICACHE_FLASH_ATTR MQTT_OnData(MQTT_Client *mqttClient, MqttDataCallback dataCb);\nBOOL ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client *client, char* topic, uint8_t qos);\nvoid ICACHE_FLASH_ATTR MQTT_Connect(MQTT_Client *mqttClient);\nvoid ICACHE_FLASH_ATTR MQTT_Disconnect(MQTT_Client *mqttClient);\nBOOL ICACHE_FLASH_ATTR MQTT_Publish(MQTT_Client *client, const char* topic, const char* data, int data_length, int qos, int retain);\n\n#endif /* USER_AT_MQTT_H_ */\n"
  },
  {
    "path": "app/mqtt/mqtt_msg.c",
    "content": "/*\n* Copyright (c) 2014, Stephen Robinson\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n* 1. Redistributions of source code must retain the above copyright\n* notice, this list of conditions and the following disclaimer.\n* 2. Redistributions in binary form must reproduce the above copyright\n* notice, this list of conditions and the following disclaimer in the\n* documentation and/or other materials provided with the distribution.\n* 3. Neither the name of the copyright holder nor the names of its\n* contributors may be used to endorse or promote products derived\n* from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n* POSSIBILITY OF SUCH DAMAGE.\n*\n*/\n\n#include <string.h>\n#include \"mqtt_msg.h\"\n#include \"user_config.h\"\n#define MQTT_MAX_FIXED_HEADER_SIZE 3\n\nenum mqtt_connect_flag\n{\n  MQTT_CONNECT_FLAG_USERNAME = 1 << 7,\n  MQTT_CONNECT_FLAG_PASSWORD = 1 << 6,\n  MQTT_CONNECT_FLAG_WILL_RETAIN = 1 << 5,\n  MQTT_CONNECT_FLAG_WILL = 1 << 2,\n  MQTT_CONNECT_FLAG_CLEAN_SESSION = 1 << 1\n};\n\nstruct __attribute((__packed__)) mqtt_connect_variable_header\n{\n  uint8_t lengthMsb;\n  uint8_t lengthLsb;\n#if defined(PROTOCOL_NAMEv31)\n  uint8_t magic[6];\n#elif defined(PROTOCOL_NAMEv311)\n  uint8_t magic[4];\n#else\n#error \"Please define protocol name\"\n#endif\n  uint8_t version;\n  uint8_t flags;\n  uint8_t keepaliveMsb;\n  uint8_t keepaliveLsb;\n};\n\nstatic int ICACHE_FLASH_ATTR append_string(mqtt_connection_t* connection, const char* string, int len)\n{\n  if(connection->message.length + len + 2 > connection->buffer_length)\n    return -1;\n\n  connection->buffer[connection->message.length++] = len >> 8;\n  connection->buffer[connection->message.length++] = len & 0xff;\n  memcpy(connection->buffer + connection->message.length, string, len);\n  connection->message.length += len;\n\n  return len + 2;\n}\n\nstatic uint16_t ICACHE_FLASH_ATTR append_message_id(mqtt_connection_t* connection, uint16_t message_id)\n{\n  // If message_id is zero then we should assign one, otherwise\n  // we'll use the one supplied by the caller\n  while(message_id == 0)\n    message_id = ++connection->message_id;\n\n  if(connection->message.length + 2 > connection->buffer_length)\n    return 0;\n\n  connection->buffer[connection->message.length++] = message_id >> 8;\n  connection->buffer[connection->message.length++] = message_id & 0xff;\n\n  return message_id;\n}\n\nstatic int ICACHE_FLASH_ATTR init_message(mqtt_connection_t* connection)\n{\n  connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE;\n  return MQTT_MAX_FIXED_HEADER_SIZE;\n}\n\nstatic mqtt_message_t* ICACHE_FLASH_ATTR fail_message(mqtt_connection_t* connection)\n{\n  connection->message.data = connection->buffer;\n  connection->message.length = 0;\n  return &connection->message;\n}\n\nstatic mqtt_message_t* ICACHE_FLASH_ATTR fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain)\n{\n  int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE;\n\n  if(remaining_length > 127)\n  {\n    connection->buffer[0] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);\n    connection->buffer[1] = 0x80 | (remaining_length % 128);\n    connection->buffer[2] = remaining_length / 128;\n    connection->message.length = remaining_length + 3;\n    connection->message.data = connection->buffer;\n  }\n  else\n  {\n    connection->buffer[1] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1);\n    connection->buffer[2] = remaining_length;\n    connection->message.length = remaining_length + 2;\n    connection->message.data = connection->buffer + 1;\n  }\n\n  return &connection->message;\n}\n\nvoid ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length)\n{\n  memset(connection, 0, sizeof(connection));\n  connection->buffer = buffer;\n  connection->buffer_length = buffer_length;\n}\n\nint ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length)\n{\n  int i;\n  int totlen = 0;\n\n  for(i = 1; i < length; ++i)\n  {\n    totlen += (buffer[i] & 0x7f) << (7 * (i - 1));\n    if((buffer[i] & 0x80) == 0)\n    {\n      ++i;\n      break;\n    }\n  }\n  totlen += i;\n\n  return totlen;\n}\n\nconst char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length)\n{\n  int i;\n  int totlen = 0;\n  int topiclen;\n\n  for(i = 1; i < *length; ++i)\n  {\n    totlen += (buffer[i] & 0x7f) << (7 * (i -1));\n    if((buffer[i] & 0x80) == 0)\n    {\n      ++i;\n      break;\n    }\n  }\n  totlen += i;\n\n  if(i + 2 >= *length)\n    return NULL;\n  topiclen = buffer[i++] << 8;\n  topiclen |= buffer[i++];\n\n  if(i + topiclen > *length)\n    return NULL;\n\n  *length = topiclen;\n  return (const char*)(buffer + i);\n}\n\nconst char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length)\n{\n  int i;\n  int totlen = 0;\n  int topiclen;\n\n  for(i = 1; i < *length; ++i)\n  {\n    totlen += (buffer[i] & 0x7f) << (7 * (i - 1));\n    if((buffer[i] & 0x80) == 0)\n    {\n      ++i;\n      break;\n    }\n  }\n  totlen += i;\n\n  if(i + 2 >= *length)\n    return NULL;\n  topiclen = buffer[i++] << 8;\n  topiclen |= buffer[i++];\n\n  if(i + topiclen >= *length){\n\t*length = 0;\n    return NULL;\n  }\n  i += topiclen;\n\n  if(mqtt_get_qos(buffer) > 0)\n  {\n    if(i + 2 >= *length)\n      return NULL;\n    i += 2;\n  }\n\n  if(totlen < i)\n    return NULL;\n\n  if(totlen <= *length)\n    *length = totlen - i;\n  else\n    *length = *length - i;\n  return (const char*)(buffer + i);\n}\n\nuint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length)\n{\n  if(length < 1)\n    return 0;\n\n  switch(mqtt_get_type(buffer))\n  {\n    case MQTT_MSG_TYPE_PUBLISH:\n    {\n      int i;\n      int topiclen;\n\n      for(i = 1; i < length; ++i)\n      {\n        if((buffer[i] & 0x80) == 0)\n        {\n          ++i;\n          break;\n        }\n      }\n\n      if(i + 2 >= length)\n        return 0;\n      topiclen = buffer[i++] << 8;\n      topiclen |= buffer[i++];\n\n      if(i + topiclen >= length)\n        return 0;\n      i += topiclen;\n\n      if(mqtt_get_qos(buffer) > 0)\n      {\n        if(i + 2 >= length)\n          return 0;\n        //i += 2;\n      } else {\n    \t  return 0;\n      }\n\n      return (buffer[i] << 8) | buffer[i + 1];\n    }\n    case MQTT_MSG_TYPE_PUBACK:\n    case MQTT_MSG_TYPE_PUBREC:\n    case MQTT_MSG_TYPE_PUBREL:\n    case MQTT_MSG_TYPE_PUBCOMP:\n    case MQTT_MSG_TYPE_SUBACK:\n    case MQTT_MSG_TYPE_UNSUBACK:\n    case MQTT_MSG_TYPE_SUBSCRIBE:\n    {\n      // This requires the remaining length to be encoded in 1 byte,\n      // which it should be.\n      if(length >= 4 && (buffer[1] & 0x80) == 0)\n        return (buffer[2] << 8) | buffer[3];\n      else\n        return 0;\n    }\n\n    default:\n      return 0;\n  }\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info)\n{\n  struct mqtt_connect_variable_header* variable_header;\n\n  init_message(connection);\n\n  if(connection->message.length + sizeof(*variable_header) > connection->buffer_length)\n    return fail_message(connection);\n  variable_header = (void*)(connection->buffer + connection->message.length);\n  connection->message.length += sizeof(*variable_header);\n\n  variable_header->lengthMsb = 0;\n#if defined(PROTOCOL_NAMEv31)\n  variable_header->lengthLsb = 6;\n  memcpy(variable_header->magic, \"MQIsdp\", 6);\n  variable_header->version = 3;\n#elif defined(PROTOCOL_NAMEv311)\n  variable_header->lengthLsb = 4;\n  memcpy(variable_header->magic, \"MQTT\", 4);\n  variable_header->version = 4;\n#else\n#error \"Please define protocol name\"\n#endif\n\n  variable_header->flags = 0;\n  variable_header->keepaliveMsb = info->keepalive >> 8;\n  variable_header->keepaliveLsb = info->keepalive & 0xff;\n\n  if(info->clean_session)\n    variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION;\n\n  if(info->client_id != NULL && info->client_id[0] != '\\0')\n  {\n    if(append_string(connection, info->client_id, strlen(info->client_id)) < 0)\n      return fail_message(connection);\n  }\n  else\n    return fail_message(connection);\n\n  if(info->will_topic != NULL && info->will_topic[0] != '\\0')\n  {\n    if(append_string(connection, info->will_topic, strlen(info->will_topic)) < 0)\n      return fail_message(connection);\n\n    if(append_string(connection, info->will_message, strlen(info->will_message)) < 0)\n      return fail_message(connection);\n\n    variable_header->flags |= MQTT_CONNECT_FLAG_WILL;\n    if(info->will_retain)\n      variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN;\n    variable_header->flags |= (info->will_qos & 3) << 3;\n  }\n\n  if(info->username != NULL && info->username[0] != '\\0')\n  {\n    if(append_string(connection, info->username, strlen(info->username)) < 0)\n      return fail_message(connection);\n\n    variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME;\n  }\n\n  if(info->password != NULL && info->password[0] != '\\0')\n  {\n    if(append_string(connection, info->password, strlen(info->password)) < 0)\n      return fail_message(connection);\n\n    variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD;\n  }\n\n  return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id)\n{\n  init_message(connection);\n\n  if(topic == NULL || topic[0] == '\\0')\n    return fail_message(connection);\n\n  if(append_string(connection, topic, strlen(topic)) < 0)\n    return fail_message(connection);\n\n  if(qos > 0)\n  {\n    if((*message_id = append_message_id(connection, 0)) == 0)\n      return fail_message(connection);\n  }\n  else\n    *message_id = 0;\n\n  if(connection->message.length + data_length > connection->buffer_length)\n    return fail_message(connection);\n  memcpy(connection->buffer + connection->message.length, data, data_length);\n  connection->message.length += data_length;\n\n  return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id)\n{\n  init_message(connection);\n  if(append_message_id(connection, message_id) == 0)\n    return fail_message(connection);\n  return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id)\n{\n  init_message(connection);\n  if(append_message_id(connection, message_id) == 0)\n    return fail_message(connection);\n  return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id)\n{\n  init_message(connection);\n  if(append_message_id(connection, message_id) == 0)\n    return fail_message(connection);\n  return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id)\n{\n  init_message(connection);\n  if(append_message_id(connection, message_id) == 0)\n    return fail_message(connection);\n  return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id)\n{\n  init_message(connection);\n\n  if(topic == NULL || topic[0] == '\\0')\n    return fail_message(connection);\n\n  if((*message_id = append_message_id(connection, 0)) == 0)\n    return fail_message(connection);\n\n  if(append_string(connection, topic, strlen(topic)) < 0)\n    return fail_message(connection);\n\n  if(connection->message.length + 1 > connection->buffer_length)\n    return fail_message(connection);\n  connection->buffer[connection->message.length++] = qos;\n\n  return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id)\n{\n  init_message(connection);\n\n  if(topic == NULL || topic[0] == '\\0')\n    return fail_message(connection);\n\n  if((*message_id = append_message_id(connection, 0)) == 0)\n    return fail_message(connection);\n\n  if(append_string(connection, topic, strlen(topic)) < 0)\n    return fail_message(connection);\n\n  return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection)\n{\n  init_message(connection);\n  return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection)\n{\n  init_message(connection);\n  return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0);\n}\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection)\n{\n  init_message(connection);\n  return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0);\n}\n"
  },
  {
    "path": "app/mqtt/mqtt_msg.h",
    "content": "/* \n * File:   mqtt_msg.h\n * Author: Minh Tuan\n *\n * Created on July 12, 2014, 1:05 PM\n */\n\n#ifndef MQTT_MSG_H\n#define\tMQTT_MSG_H\n#include \"c_types.h\"\n#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n/*\n* Copyright (c) 2014, Stephen Robinson\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n* 1. Redistributions of source code must retain the above copyright\n* notice, this list of conditions and the following disclaimer.\n* 2. Redistributions in binary form must reproduce the above copyright\n* notice, this list of conditions and the following disclaimer in the\n* documentation and/or other materials provided with the distribution.\n* 3. Neither the name of the copyright holder nor the names of its\n* contributors may be used to endorse or promote products derived\n* from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n* POSSIBILITY OF SUCH DAMAGE.\n*\n*/\n/* 7\t\t\t6\t\t\t5\t\t\t4\t\t\t3\t\t\t2\t\t\t1\t\t\t0*/\n/*|      --- Message Type----\t\t\t|  DUP Flag\t|\t   QoS Level\t\t|\tRetain\t|\n/*\t\t\t\t\t\t\t\t\t\tRemaining Length\t\t\t\t\t\t\t\t */\n\n#define PROTOCOL_NAMEv31  /*MQTT version 3.1 compatible with Mosquitto v0.15*/\n\nenum mqtt_message_type\n{\n  MQTT_MSG_TYPE_CONNECT = 1,\n  MQTT_MSG_TYPE_CONNACK = 2,\n  MQTT_MSG_TYPE_PUBLISH = 3,\n  MQTT_MSG_TYPE_PUBACK = 4,\n  MQTT_MSG_TYPE_PUBREC = 5,\n  MQTT_MSG_TYPE_PUBREL = 6,\n  MQTT_MSG_TYPE_PUBCOMP = 7,\n  MQTT_MSG_TYPE_SUBSCRIBE = 8,\n  MQTT_MSG_TYPE_SUBACK = 9,\n  MQTT_MSG_TYPE_UNSUBSCRIBE = 10,\n  MQTT_MSG_TYPE_UNSUBACK = 11,\n  MQTT_MSG_TYPE_PINGREQ = 12,\n  MQTT_MSG_TYPE_PINGRESP = 13,\n  MQTT_MSG_TYPE_DISCONNECT = 14\n};\n\ntypedef struct mqtt_message\n{\n  uint8_t* data;\n  uint16_t length;\n\n} mqtt_message_t;\n\ntypedef struct mqtt_connection\n{\n  mqtt_message_t message;\n\n  uint16_t message_id;\n  uint8_t* buffer;\n  uint16_t buffer_length;\n\n} mqtt_connection_t;\n\ntypedef struct mqtt_connect_info\n{\n  char* client_id;\n  char* username;\n  char* password;\n  char* will_topic;\n  char* will_message;\n  int keepalive;\n  int will_qos;\n  int will_retain;\n  int clean_session;\n\n} mqtt_connect_info_t;\n\n\nstatic inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) { return (buffer[0] & 0xf0) >> 4; }\nstatic inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) { return (buffer[0] & 0x08) >> 3; }\nstatic inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) { return (buffer[0] & 0x06) >> 1; }\nstatic inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) { return (buffer[0] & 0x01); }\n\nvoid ICACHE_FLASH_ATTR mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);\nint ICACHE_FLASH_ATTR mqtt_get_total_length(uint8_t* buffer, uint16_t length);\nconst char* ICACHE_FLASH_ATTR mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);\nconst char* ICACHE_FLASH_ATTR mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);\nuint16_t ICACHE_FLASH_ATTR mqtt_get_id(uint8_t* buffer, uint16_t length);\n\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingreq(mqtt_connection_t* connection);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection);\nmqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection);\n\n\n#ifdef\t__cplusplus\n}\n#endif\n\n#endif\t/* MQTT_MSG_H */\n\n"
  },
  {
    "path": "app/mqtt/proto.c",
    "content": "#include \"proto.h\"\n#include \"ringbuf.h\"\nI8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize)\n{\n    parser->buf = buf;\n    parser->bufSize = bufSize;\n    parser->dataLen = 0;\n    parser->callback = completeCallback;\n    parser->isEsc = 0;\n    return 0;\n}\n\nI8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value)\n{\t\n\tswitch(value){\n\t\tcase 0x7D:\n\t\t\tparser->isEsc = 1;\n\t\t\tbreak;\n\t\t\n\t\tcase 0x7E:\n\t\t\tparser->dataLen = 0;\n\t\t\tparser->isEsc = 0;\n\t\t\tparser->isBegin = 1;\n\t\t\tbreak;\n\t\t\n\t\tcase 0x7F:\n\t\t\tif (parser->callback != NULL)\n\t\t\t\tparser->callback();\n\t\t\tparser->isBegin = 0;\n\t\t\treturn 0;\n\t\t\tbreak;\n\t\t\n\t\tdefault:\n\t\t\tif(parser->isBegin == 0) break;\n\t\t\t\n\t\t\tif(parser->isEsc){\n\t\t\t\tvalue ^= 0x20;\n\t\t\t\tparser->isEsc = 0;\n\t\t\t}\n\t\t\t\t\n\t\t\tif(parser->dataLen < parser->bufSize)\n\t\t\t\tparser->buf[parser->dataLen++] = value;\n\t\t\t\t\n\t\t\tbreak;\n\t}\n    return -1;\n}\n\nI8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len)\n{\n    while(len--)\n        PROTO_ParseByte(parser, *buf++);\n\n    return 0;\n}\nI16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF* rb, U8 *bufOut, U16* len, U16 maxBufLen)\n{\n\tU8 c;\n\n\tPROTO_PARSER proto;\n\tPROTO_Init(&proto, NULL, bufOut, maxBufLen);\n\twhile(RINGBUF_Get(rb, &c) == 0){\n\t\tif(PROTO_ParseByte(&proto, c) == 0){\n\t\t\t*len = proto.dataLen;\n\t\t\treturn 0;\n\t\t}\n\t}\n\treturn -1;\n}\nI16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize)\n{\n    U16 i = 2;\n    U16 len = *(U16*) packet;\n\n    if (bufSize < 1) return -1;\n\n    *buf++ = 0x7E;\n    bufSize--;\n\n    while (len--) {\n        switch (*packet) {\n        case 0x7D:\n        case 0x7E:\n        case 0x7F:\n            if (bufSize < 2) return -1;\n            *buf++ = 0x7D;\n            *buf++ = *packet++ ^ 0x20;\n            i += 2;\n            bufSize -= 2;\n            break;\n        default:\n            if (bufSize < 1) return -1;\n            *buf++ = *packet++;\n            i++;\n            bufSize--;\n            break;\n        }\n    }\n\n    if (bufSize < 1) return -1;\n    *buf++ = 0x7F;\n\n    return i;\n}\n\nI16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len)\n{\n    U16 i = 2;\n    if(RINGBUF_Put(rb, 0x7E) == -1) return -1;\n    while (len--) {\n        switch (*packet) {\n        case 0x7D:\n        case 0x7E:\n        case 0x7F:\n        \tif(RINGBUF_Put(rb, 0x7D) == -1) return -1;\n        \tif(RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1;\n            i += 2;\n            break;\n        default:\n        \tif(RINGBUF_Put(rb, *packet++) == -1) return -1;\n            i++;\n            break;\n        }\n    }\n    if(RINGBUF_Put(rb, 0x7F) == -1) return -1;\n\n    return i;\n}\n\n"
  },
  {
    "path": "app/mqtt/proto.h",
    "content": "/* \n * File:   proto.h\n * Author: ThuHien\n *\n * Created on November 23, 2012, 8:57 AM\n */\n\n#ifndef _PROTO_H_\n#define\t_PROTO_H_\n#include <stdlib.h>\n#include \"typedef.h\"\n#include \"ringbuf.h\"\n\ntypedef void(PROTO_PARSE_CALLBACK)();\n\ntypedef struct{\n\tU8 *buf;\n\tU16 bufSize;\n\tU16 dataLen;\n\tU8 isEsc;\n\tU8 isBegin;\n\tPROTO_PARSE_CALLBACK* callback;\n}PROTO_PARSER;\n\nI8 ICACHE_FLASH_ATTR PROTO_Init(PROTO_PARSER *parser, PROTO_PARSE_CALLBACK *completeCallback, U8 *buf, U16 bufSize);\nI8 ICACHE_FLASH_ATTR PROTO_Parse(PROTO_PARSER *parser, U8 *buf, U16 len);\nI16 ICACHE_FLASH_ATTR PROTO_Add(U8 *buf, const U8 *packet, I16 bufSize);\nI16 ICACHE_FLASH_ATTR PROTO_AddRb(RINGBUF *rb, const U8 *packet, I16 len);\nI8 ICACHE_FLASH_ATTR PROTO_ParseByte(PROTO_PARSER *parser, U8 value);\nI16 ICACHE_FLASH_ATTR PROTO_ParseRb(RINGBUF *rb, U8 *bufOut, U16* len, U16 maxBufLen);\n#endif\n\n"
  },
  {
    "path": "app/mqtt/queue.c",
    "content": "/* str_queue.c\n*\n* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions are met:\n*\n* * Redistributions of source code must retain the above copyright notice,\n* this list of conditions and the following disclaimer.\n* * Redistributions in binary form must reproduce the above copyright\n* notice, this list of conditions and the following disclaimer in the\n* documentation and/or other materials provided with the distribution.\n* * Neither the name of Redis nor the names of its contributors may be used\n* to endorse or promote products derived from this software without\n* specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n* POSSIBILITY OF SUCH DAMAGE.\n*/\n#include \"queue.h\"\n\n#include \"user_interface.h\"\n#include \"osapi.h\"\n#include \"os_type.h\"\n#include \"mem.h\"\n#include \"proto.h\"\nvoid ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize)\n{\n\tqueue->buf = (uint8_t*)os_zalloc(bufferSize);\n\tRINGBUF_Init(&queue->rb, queue->buf, bufferSize);\n}\nint32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len)\n{\n\treturn PROTO_AddRb(&queue->rb, buffer, len);\n}\nint32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen)\n{\n\n\treturn PROTO_ParseRb(&queue->rb, buffer, len, maxLen);\n}\n\nBOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue)\n{\n\tif(queue->rb.fill_cnt<=0)\n\t\treturn TRUE;\n\treturn FALSE;\n}\n"
  },
  {
    "path": "app/mqtt/queue.h",
    "content": "/* str_queue.h --\n*\n* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions are met:\n*\n* * Redistributions of source code must retain the above copyright notice,\n* this list of conditions and the following disclaimer.\n* * Redistributions in binary form must reproduce the above copyright\n* notice, this list of conditions and the following disclaimer in the\n* documentation and/or other materials provided with the distribution.\n* * Neither the name of Redis nor the names of its contributors may be used\n* to endorse or promote products derived from this software without\n* specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n* POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#ifndef USER_QUEUE_H_\n#define USER_QUEUE_H_\n#include \"os_type.h\"\n#include \"ringbuf.h\"\ntypedef struct {\n\tuint8_t *buf;\n\tRINGBUF rb;\n} QUEUE;\n\nvoid ICACHE_FLASH_ATTR QUEUE_Init(QUEUE *queue, int bufferSize);\nint32_t ICACHE_FLASH_ATTR QUEUE_Puts(QUEUE *queue, uint8_t* buffer, uint16_t len);\nint32_t ICACHE_FLASH_ATTR QUEUE_Gets(QUEUE *queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen);\nBOOL ICACHE_FLASH_ATTR QUEUE_IsEmpty(QUEUE *queue);\n#endif /* USER_QUEUE_H_ */\n"
  },
  {
    "path": "app/mqtt/ringbuf.c",
    "content": "/**\n* \\file\n*\t\tRing Buffer library\n*/\n\n#include \"ringbuf.h\"\n\n\n/**\n* \\brief init a RINGBUF object\n* \\param r pointer to a RINGBUF object\n* \\param buf pointer to a byte array\n* \\param size size of buf\n* \\return 0 if successfull, otherwise failed\n*/\nI16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size)\n{\n\tif(r == NULL || buf == NULL || size < 2) return -1;\n\t\n\tr->p_o = r->p_r = r->p_w = buf;\n\tr->fill_cnt = 0;\n\tr->size = size;\n\t\n\treturn 0;\n}\n/**\n* \\brief put a character into ring buffer\n* \\param r pointer to a ringbuf object\n* \\param c character to be put\n* \\return 0 if successfull, otherwise failed\n*/\nI16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c)\n{\n\tif(r->fill_cnt>=r->size)return -1;\t\t// ring buffer is full, this should be atomic operation\n\t\n\n\tr->fill_cnt++;\t\t\t\t\t\t\t// increase filled slots count, this should be atomic operation\n\n\t\n\t*r->p_w++ = c;\t\t\t\t\t\t\t// put character into buffer\n\t\n\tif(r->p_w >= r->p_o + r->size)\t\t\t// rollback if write pointer go pass\n\t\tr->p_w = r->p_o;\t\t\t\t\t// the physical boundary\n\t\n\treturn 0;\n}\n/**\n* \\brief get a character from ring buffer\n* \\param r pointer to a ringbuf object\n* \\param c read character\n* \\return 0 if successfull, otherwise failed\n*/\nI16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c)\n{\n\tif(r->fill_cnt<=0)return -1;\t\t\t\t// ring buffer is empty, this should be atomic operation\n\t\n\n\tr->fill_cnt--;\t\t\t\t\t\t\t\t// decrease filled slots count\n\n\t\n\t*c = *r->p_r++;\t\t\t\t\t\t\t\t// get the character out\n\t\n\tif(r->p_r >= r->p_o + r->size)\t\t\t\t// rollback if write pointer go pass\n\t\tr->p_r = r->p_o;\t\t\t\t\t\t// the physical boundary\n\t\n\treturn 0;\n}\n"
  },
  {
    "path": "app/mqtt/ringbuf.h",
    "content": "#ifndef _RING_BUF_H_\n#define _RING_BUF_H_\n\n#include <os_type.h>\n#include <stdlib.h>\n#include \"typedef.h\"\n\ntypedef struct{\n\tU8* p_o;\t\t\t\t/**< Original pointer */\n\tU8* volatile p_r;\t\t/**< Read pointer */\n\tU8* volatile p_w;\t\t/**< Write pointer */\n\tvolatile I32 fill_cnt;\t/**< Number of filled slots */\n\tI32 size;\t\t\t\t/**< Buffer size */\n}RINGBUF;\n\nI16 ICACHE_FLASH_ATTR RINGBUF_Init(RINGBUF *r, U8* buf, I32 size);\nI16 ICACHE_FLASH_ATTR RINGBUF_Put(RINGBUF *r, U8 c);\nI16 ICACHE_FLASH_ATTR RINGBUF_Get(RINGBUF *r, U8* c);\n#endif\n"
  },
  {
    "path": "app/mqtt/typedef.h",
    "content": "/**\n* \\file\n*\t\tStandard Types definition\n*/\n\n#ifndef _TYPE_DEF_H_\n#define _TYPE_DEF_H_\n\ntypedef char I8;\ntypedef unsigned char U8;\ntypedef short I16;\ntypedef unsigned short U16;\ntypedef long I32;\ntypedef unsigned long U32;\ntypedef unsigned long long U64;\n\n#endif\n"
  },
  {
    "path": "app/mqtt/utils.c",
    "content": "/*\n* Copyright (c) 2014, Tuan PM\n* Email: tuanpm@live.com\n*\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n* 1. Redistributions of source code must retain the above copyright\n* notice, this list of conditions and the following disclaimer.\n* 2. Redistributions in binary form must reproduce the above copyright\n* notice, this list of conditions and the following disclaimer in the\n* documentation and/or other materials provided with the distribution.\n* 3. Neither the name of the copyright holder nor the names of its\n* contributors may be used to endorse or promote products derived\n* from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n* POSSIBILITY OF SUCH DAMAGE.\n*\n*/\n#include <string.h>\n#include <stdio.h>\n#include <ctype.h>\n#include <math.h>\n#include <stddef.h>\n#include \"utils.h\"\n\n\nuint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str)\n{\n\tuint8_t segs = 0;   /* Segment count. */\n\tuint8_t chcnt = 0;  /* Character count within segment. */\n\tuint8_t accum = 0;  /* Accumulator for segment. */\n    /* Catch NULL pointer. */\n    if (str == 0)\n        return 0;\n    /* Process every character in string. */\n\n    while (*str != '\\0') {\n        /* Segment changeover. */\n\n        if (*str == '.') {\n            /* Must have some digits in segment. */\n            if (chcnt == 0)\n                return 0;\n            /* Limit number of segments. */\n            if (++segs == 4)\n                return 0;\n            /* Reset segment values and restart loop. */\n            chcnt = accum = 0;\n            str++;\n            continue;\n        }\n\n        /* Check numeric. */\n        if ((*str < '0') || (*str > '9'))\n            return 0;\n\n        /* Accumulate and check segment. */\n\n        if ((accum = accum * 10 + *str - '0') > 255)\n            return 0;\n        /* Advance other segment specific stuff and continue loop. */\n\n        chcnt++;\n        str++;\n    }\n\n    /* Check enough segments and enough characters in last segment. */\n\n    if (segs != 3)\n        return 0;\n    if (chcnt == 0)\n        return 0;\n    /* Address okay. */\n\n    return 1;\n}\nuint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip)\n{\n\n\t    /* The count of the number of bytes processed. */\n\t    int i;\n\t    /* A pointer to the next digit to process. */\n\t    const char * start;\n\n\t    start = str;\n\t    for (i = 0; i < 4; i++) {\n\t        /* The digit being processed. */\n\t        char c;\n\t        /* The value of this byte. */\n\t        int n = 0;\n\t        while (1) {\n\t            c = * start;\n\t            start++;\n\t            if (c >= '0' && c <= '9') {\n\t                n *= 10;\n\t                n += c - '0';\n\t            }\n\t            /* We insist on stopping at \".\" if we are still parsing\n\t               the first, second, or third numbers. If we have reached\n\t               the end of the numbers, we will allow any character. */\n\t            else if ((i < 3 && c == '.') || i == 3) {\n\t                break;\n\t            }\n\t            else {\n\t                return 0;\n\t            }\n\t        }\n\t        if (n >= 256) {\n\t            return 0;\n\t        }\n\t        ((uint8_t*)ip)[i] = n;\n\t    }\n\t    return 1;\n\n}\nuint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s)\n{\n\tuint32_t value = 0, digit;\n\tint8_t c;\n\t\n\twhile((c = *s++)){\n\t\tif('0' <= c && c <= '9')\n\t\t\tdigit = c - '0';\n\t\telse if('A' <= c && c <= 'F')\n\t\t\tdigit = c - 'A' + 10;\n\t\telse if('a' <= c && c<= 'f')\n\t\t\tdigit = c - 'a' + 10;\n\t\telse break;\n\t\t\n\t\tvalue = (value << 4) | digit;\n\t}\n\t\n\treturn value;\n}\n\n"
  },
  {
    "path": "app/mqtt/utils.h",
    "content": "#ifndef _UTILS_H_\n#define\t_UTILS_H_\n\n#include \"c_types.h\"\n\nuint32_t ICACHE_FLASH_ATTR UTILS_Atoh(const int8_t *s);\nuint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const int8_t* str, void *ip);\nuint8_t ICACHE_FLASH_ATTR UTILS_IsIPV4 (int8_t *str);\n#endif\n"
  },
  {
    "path": "app/platform/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = libplatform.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../wofs\nINCLUDES += -I ../spiffs\nINCLUDES += -I ../libc\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/platform/common.c",
    "content": "// Common code for all backends\n\n#include \"platform.h\"\n#include \"common.h\"\n#include \"c_string.h\"\n#include \"c_stdio.h\"\n#include \"cpu_esp8266.h\"\n\nvoid cmn_platform_init(void)\n{\n\n}\n\n// ****************************************************************************\n// GPIO functions\n\nint platform_gpio_exists( unsigned pin )\n{\n  return pin < NUM_GPIO;\n}\n\n// ****************************************************************************\n// CAN functions\n\nint platform_can_exists( unsigned id )\n{\n  return id < NUM_CAN;\n}\n\n// ****************************************************************************\n// SPI functions\n\n\nint platform_spi_exists( unsigned id )\n{\n  return id < NUM_SPI;\n}\n\n// ****************************************************************************\n// PWM functions\n\nint platform_pwm_exists( unsigned id )\n{\n  return ((id < NUM_PWM) && (id > 0));\n}\n\n// ****************************************************************************\n// ADC functions\n\nint platform_adc_exists( unsigned id )\n{\n  return id < NUM_ADC;\n}\n\n// ****************************************************************************\n// UART functions\n\nint platform_uart_exists( unsigned id )\n{\n  return id < NUM_UART;\n}\n\n// ****************************************************************************\n// OneWire functions\n\nint platform_ow_exists( unsigned id )\n{\n  return ((id < NUM_OW) && (id > 0));\n}\n\n// ****************************************************************************\n// Timer functions\n\nint platform_tmr_exists( unsigned id )\n{\n  return id < NUM_TMR;\n}\n\n// I2C support\nint platform_i2c_exists( unsigned id )\n{\n#ifndef NUM_I2C\n  return 0;\n#else\n  return id < NUM_I2C;\n#endif\n}\n\n// ****************************************************************************\n// Internal flash support functions\n\n// This symbol must be exported by the linker command file and must reflect the\n// TOTAL size of flash used by the eLua image (not only the code and constants,\n// but also .data and whatever else ends up in the eLua image). FS will start\n// at the next usable (aligned to a flash sector boundary) address after \n// flash_used_size.\n\n// extern char flash_used_size[];\nextern char _flash_used_end[];\n\n// Helper function: find the flash sector in which an address resides\n// Return the sector number, as well as the start and end address of the sector\nstatic uint32_t flashh_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend )\n{\n  address -= INTERNAL_FLASH_START_ADDRESS;\n#ifdef INTERNAL_FLASH_SECTOR_SIZE\n  // All the sectors in the flash have the same size, so just align the address\n  uint32_t sect_id = address / INTERNAL_FLASH_SECTOR_SIZE;\n\n  if( pstart )\n    *pstart = sect_id * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS;\n  if( pend )\n    *pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE + INTERNAL_FLASH_START_ADDRESS - 1;\n  return sect_id;\n#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE\n  // The flash has blocks of different size\n  // Their size is decribed in the INTERNAL_FLASH_SECTOR_ARRAY macro\n  const uint32_t flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;\n  uint32_t total = 0, i = 0;\n\n  while( ( total <= address ) && ( i < sizeof( flash_sect_size ) / sizeof( uint32_t ) ) )\n    total += flash_sect_size[ i ++ ];\n  if( pstart )\n    *pstart = ( total - flash_sect_size[ i - 1 ] ) + INTERNAL_FLASH_START_ADDRESS;\n  if( pend )\n    *pend = total + INTERNAL_FLASH_START_ADDRESS - 1;\n  return i - 1;\n#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE\n}\n\nuint32_t platform_flash_get_sector_of_address( uint32_t addr )\n{\n  return flashh_find_sector( addr, NULL, NULL );\n}\n\nuint32_t platform_flash_get_num_sectors(void)\n{\n#ifdef INTERNAL_FLASH_SECTOR_SIZE\n  return INTERNAL_FLASH_SIZE / INTERNAL_FLASH_SECTOR_SIZE;\n#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE\n  const uint32_t flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;\n\n  return sizeof( flash_sect_size ) / sizeof( uint32_t );\n#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE\n}\n\nuint32_t platform_flash_get_first_free_block_address( uint32_t *psect )\n{\n  // Round the total used flash size to the closest flash block address\n  uint32_t start, end, sect;\n  NODE_DBG(\"_flash_used_end:%08x\", (uint32_t)_flash_used_end);\n  if(_flash_used_end>0){ // find the used sector\n    // sect = flashh_find_sector( ( uint32_t )flash_used_size + INTERNAL_FLASH_START_ADDRESS - 1, NULL, &end );\n    sect = flashh_find_sector( ( uint32_t )_flash_used_end - 1, NULL, &end );\n    if( psect )\n      *psect = sect + 1;    \n    return end + 1;\n  }else{\n    sect = flashh_find_sector( INTERNAL_FLASH_START_ADDRESS, &start, NULL ); // find the first free sector\n    if( psect )\n      *psect = sect;   \n    return start;\n  }\n}\n\nuint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size )\n{\n#ifndef INTERNAL_FLASH_WRITE_UNIT_SIZE\n  return platform_s_flash_write( from, toaddr, size );\n#else // #ifindef INTERNAL_FLASH_WRITE_UNIT_SIZE\n  uint32_t temp, rest, ssize = size;\n  unsigned i;\n  char tmpdata[ INTERNAL_FLASH_WRITE_UNIT_SIZE ];\n  const uint8_t *pfrom = ( const uint8_t* )from;\n  const uint32_t blksize = INTERNAL_FLASH_WRITE_UNIT_SIZE;\n  const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1;\n\n  // Align the start\n  if( toaddr & blkmask )\n  {\n    rest = toaddr & blkmask;\n    temp = toaddr & ~blkmask; // this is the actual aligned address\n    // c_memcpy( tmpdata, ( const void* )temp, blksize );\n    platform_s_flash_read( tmpdata, temp, blksize );\n    for( i = rest; size && ( i < blksize ); i ++, size --, pfrom ++ )\n      tmpdata[ i ] = *pfrom;\n    platform_s_flash_write( tmpdata, temp, blksize );\n    if( size == 0 )\n      return ssize;\n    toaddr = temp + blksize;\n  }\n  // The start address is now a multiple of blksize\n  // Compute how many bytes we can write as multiples of blksize\n  rest = size & blkmask;\n  temp = size & ~blkmask;\n  // Program the blocks now\n  if( temp )\n  {\n    platform_s_flash_write( pfrom, toaddr, temp );\n    toaddr += temp;\n    pfrom += temp;\n  }\n  // And the final part of a block if needed\n  if( rest )\n  {\n    // c_memcpy( tmpdata, ( const void* )toaddr, blksize );\n    platform_s_flash_read( tmpdata, toaddr, blksize );\n    for( i = 0; size && ( i < rest ); i ++, size --, pfrom ++ )\n      tmpdata[ i ] = *pfrom;\n    platform_s_flash_write( tmpdata, toaddr, blksize );\n  }\n  return ssize;\n#endif // #ifndef INTERNAL_FLASH_WRITE_UNIT_SIZE\n}\n\nuint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size )\n{\n#ifndef INTERNAL_FLASH_READ_UNIT_SIZE\n  return platform_s_flash_read( to, fromaddr, size );\n#else // #ifindef INTERNAL_FLASH_READ_UNIT_SIZE\n  uint32_t temp, rest, ssize = size;\n  unsigned i;\n  char tmpdata[ INTERNAL_FLASH_READ_UNIT_SIZE ];\n  uint8_t *pto = ( uint8_t* )to;\n  const uint32_t blksize = INTERNAL_FLASH_READ_UNIT_SIZE;\n  const uint32_t blkmask = INTERNAL_FLASH_READ_UNIT_SIZE - 1;\n\n  // Align the start\n  if( fromaddr & blkmask )\n  {\n    rest = fromaddr & blkmask;\n    temp = fromaddr & ~blkmask; // this is the actual aligned address\n    platform_s_flash_read( tmpdata, temp, blksize );\n    for( i = rest; size && ( i < blksize ); i ++, size --, pto ++ )\n      *pto = tmpdata[ i ];\n    \n    if( size == 0 )\n      return ssize;\n    fromaddr = temp + blksize;\n  }\n  // The start address is now a multiple of blksize\n  // Compute how many bytes we can read as multiples of blksize\n  rest = size & blkmask;\n  temp = size & ~blkmask;\n  // Program the blocks now\n  if( temp )\n  {\n    platform_s_flash_read( pto, fromaddr, temp );\n    fromaddr += temp;\n    pto += temp;\n  }\n  // And the final part of a block if needed\n  if( rest )\n  {\n    platform_s_flash_read( tmpdata, fromaddr, blksize );\n    for( i = 0; size && ( i < rest ); i ++, size --, pto ++ )\n      *pto = tmpdata[ i ];\n  }\n  return ssize;\n#endif // #ifndef INTERNAL_FLASH_READ_UNIT_SIZE\n}\n"
  },
  {
    "path": "app/platform/common.h",
    "content": "// Common platform functions\n\n#ifndef __COMMON_H__\n#define __COMMON_H__\n\n#include \"platform.h\"\n\n// Functions exported by the common platform layer\nvoid cmn_platform_init(void);\n\n// Timer-specific functions\n\n// System timer generic implemenation\n\n// Filesystem-related functions\n\n#endif // #ifndef __COMMON_H__\n\n"
  },
  {
    "path": "app/platform/config.c",
    "content": "#include \"platform.h\"\n#include \"c_stdio.h\"\n#include \"c_string.h\"\n#include \"c_stdlib.h\"\n#include \"gpio.h\"\n#include \"user_interface.h\"\n#include \"user_config.h\"\n#include \"driver/uart.h\"\n#include \"config.h\"\n\nstatic config_data temp_data;\nuint8_t local_up_to_date=0;\nuint8_t init_ok = 0 ;\n\nvoid config_save(config_data * data){\n\n\tNODE_DBG(\"Config save\");\n\n\tplatform_flash_erase_sector(CONFIG_SECTOR);\n\t\n\tif(data!=NULL){\n\t\tplatform_flash_write((const void *)data,CONFIG_ADDRESS,sizeof(config_data));\n\t\tos_memcpy(temp_data,data,sizeof(config_data));\n\t\tlocal_up_to_date=1;\n\t}\n\telse{\n\t\t\n\t\tplatform_flash_write((const void *)&temp_data,CONFIG_ADDRESS,sizeof(config_data));\n\t}\t\t\n}\n\nstatic config_data * config_read_s(){\n\n\tplatform_s_flash_read(&temp_data,CONFIG_ADDRESS,sizeof(config_data));\n\tlocal_up_to_date=1;\n\n\treturn &temp_data;\n}\n\nconfig_data * config_read(){\n\n\tif(!init_ok){\n\t\tconfig_init();\n\t\tinit_ok=1;\n\t}\n\n\tif(!local_up_to_date)\n\t\tconfig_read_s();\n\n\treturn &temp_data;\n} \n\n\n\nvoid config_init(){\n\t\t\n\tconfig_data * config = config_read_s();\n\n\tNODE_DBG(\"Config init\");\n\n\tNODE_DBG(\"Config Magic =%08x\",config->magic);\n\n\tif(config->magic == CONFIG_MAGIC)\n\t\treturn;\t\n\n\tNODE_DBG(\"Config writing 0s\");\n\n\tos_memset(config,0,sizeof(config_data));\n\n\tconfig->magic = CONFIG_MAGIC;\n\n\tconfig_save(config);\n\n\t\n}"
  },
  {
    "path": "app/platform/config.h",
    "content": "#ifndef __CONFIG_H\n#define __CONFIG_H\n\n#include \"cpu_esp8266.h\"\n#include \"driver/relay.h\"\n\n#define CONFIG_SECTOR (FLASH_SEC_NUM - 6) //last sector\n#define CONFIG_ADDRESS (INTERNAL_FLASH_START_ADDRESS+CONFIG_SECTOR*SPI_FLASH_SEC_SIZE)\n\n#define CONFIG_MAGIC 0x1FAF15FB\t\t\t\t \n\n\n\n//4-ALIGN EVERYTHING !!\n\ntypedef struct {\n\n\tuint8_t gpioPin;\n\tuint8_t state;\n\n\tuint8_t pad[2];\n} relay;\n\ntypedef struct {\n\n\tuint32_t magic;\n\n\tstruct{\n\t\trelay relay[RELAY_COUNT];\n\t\tuint32_t init_ok;\n\t} relay_state;\n\n} config_data;\n\nvoid config_save(config_data * data);\nconfig_data * config_read();\nvoid config_init();\n\n\n\n#endif"
  },
  {
    "path": "app/platform/cpu_esp8266.h",
    "content": "#ifndef __CPU_ESP8266_H__\n#define __CPU_ESP8266_H__\n\n#include \"os_type.h\"\n#include \"spi_flash.h\"\n#include \"pin_map.h\"\n#include \"user_config.h\"\n#include \"flash_api.h\"\n// Number of resources (0 if not available/not implemented)\n#define NUM_GPIO              GPIO_PIN_NUM\n#define NUM_SPI               2\n#define NUM_UART              1\n#define NUM_PWM               GPIO_PIN_NUM\n#define NUM_ADC               1\n#define NUM_CAN               0\n#define NUM_I2C               1\n#define NUM_OW                GPIO_PIN_NUM\n#define NUM_TMR               7\n\n#if defined(FLASH_512K)\n#define FLASH_SEC_NUM \t0x80 \t// 4MByte: 0x400, 2MByte: 0x200, 1MByte: 0x100, 512KByte: 0x80\n#elif defined(FLASH_1M)\n#define FLASH_SEC_NUM \t0x100\n#elif defined(FLASH_2M)\n#define FLASH_SEC_NUM \t0x200\n#elif defined(FLASH_4M)\n#define FLASH_SEC_NUM \t0x400\n#elif defined(FLASH_AUTOSIZE)\n#define FLASH_SEC_NUM \t(flash_get_sec_num())\n#else\n#define FLASH_SEC_NUM \t0x80\n#endif\n#define SYS_PARAM_SEC_NUM 4\n#define SYS_PARAM_SEC_START (FLASH_SEC_NUM - SYS_PARAM_SEC_NUM)\n\n// #define WOFS_SEC_START\t0x80\n// #define WOFS_SEC_START\t0x60\n// #define WOFS_SEC_END\t(SYS_PARAM_SEC_START)\n// #define WOFS_SEC_NUM\t(WOFS_SEC_END - WOFS_SEC_START)\n// #define WOFS_SEC_NUM 0xc\n\n#define INTERNAL_FLASH_SECTOR_SIZE      SPI_FLASH_SEC_SIZE\n// #define INTERNAL_FLASH_SECTOR_ARRAY     { 0x4000, 0x4000, 0x4000, 0x4000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000, 0x20000 }\n#define INTERNAL_FLASH_WRITE_UNIT_SIZE  4\n#define INTERNAL_FLASH_READ_UNIT_SIZE\t4\n\n#define INTERNAL_FLASH_SIZE             ( (SYS_PARAM_SEC_START) * INTERNAL_FLASH_SECTOR_SIZE )\n#define INTERNAL_FLASH_START_ADDRESS    0x40200000\n\n// SpiFlashOpResult spi_flash_erase_sector(uint16 sec);\n// SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size);\n// SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size);\n#define flash_write spi_flash_write\n#define flash_erase spi_flash_erase_sector\n#define flash_read spi_flash_read\n\n#endif // #ifndef __CPU_ESP8266_H__\n"
  },
  {
    "path": "app/platform/flash_api.c",
    "content": "/******************************************************************************\n * Flash api for NodeMCU\n * NodeMCU Team\n * 2014-12-31\n*******************************************************************************/\n#include \"user_config.h\"\n#include \"flash_api.h\"\n#include \"spi_flash.h\"\n#include \"c_stdio.h\"\n\nstatic volatile const uint8_t flash_init_data[128] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =\n{\n    0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05,\n    0x04, 0xFE, 0xFD, 0xFF, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xE1, 0x0A, 0xFF, 0xFF, 0xF8, 0x00,\n    0xF8, 0xF8, 0x52, 0x4E, 0x4A, 0x44, 0x40, 0x38, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,\n    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0xE1, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n};\n\nSPIFlashInfo flash_get_info(void)\n{\n    volatile SPIFlashInfo spi_flash_info ICACHE_STORE_ATTR;\n    spi_flash_info = *((SPIFlashInfo *)(FLASH_MAP_START_ADDRESS));\n    return spi_flash_info;\n}\n\nuint8_t flash_get_size(void)\n{\n    return flash_get_info().size;\n}\n\nuint32_t flash_get_size_byte(void)\n{\n    uint32_t flash_size = 0;\n    switch (flash_get_info().size)\n    {\n    case SIZE_2MBIT:\n        // 2Mbit, 256kByte\n        flash_size = 256 * 1024;\n        break;\n    case SIZE_4MBIT:\n        // 4Mbit, 512kByte\n        flash_size = 512 * 1024;\n        break;\n    case SIZE_8MBIT:\n        // 8Mbit, 1MByte\n        flash_size = 1 * 1024 * 1024;\n        break;\n    case SIZE_16MBIT:\n        // 16Mbit, 2MByte\n        flash_size = 2 * 1024 * 1024;\n        break;\n    case SIZE_32MBIT:\n        // 32Mbit, 4MByte\n        flash_size = 4 * 1024 * 1024;\n        break;\n    default:\n        // Unknown flash size, fall back mode.\n        flash_size = 512 * 1024;\n        break;\n    }\n    return flash_size;\n}\n\nbool flash_set_size(uint8_t size)\n{\n    // Dangerous, here are dinosaur infested!!!!!\n    // Reboot required!!!\n    // If you don't know what you're doing, your nodemcu may turn into stone ...\n    uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR;\n    spi_flash_read(0, (uint32 *)data, sizeof(data));\n    SPIFlashInfo *p_spi_flash_info = (SPIFlashInfo *)(data);\n    p_spi_flash_info->size = size;\n    spi_flash_erase_sector(0);\n    spi_flash_write(0, (uint32 *)data, sizeof(data));\n    //p_spi_flash_info = flash_get_info();\n    //p_spi_flash_info->size = size;\n    return true;\n}\n\nbool flash_set_size_byte(uint32_t size)\n{\n    // Dangerous, here are dinosaur infested!!!!!\n    // Reboot required!!!\n    // If you don't know what you're doing, your nodemcu may turn into stone ...\n    bool result = true;\n    uint32_t flash_size = 0;\n    switch (size)\n    {\n    case 256 * 1024:\n        // 2Mbit, 256kByte\n        flash_size = SIZE_2MBIT;\n        flash_set_size(flash_size);\n        break;\n    case 512 * 1024:\n        // 4Mbit, 512kByte\n        flash_size = SIZE_4MBIT;\n        flash_set_size(flash_size);\n        break;\n    case 1 * 1024 * 1024:\n        // 8Mbit, 1MByte\n        flash_size = SIZE_8MBIT;\n        flash_set_size(flash_size);\n        break;\n    case 2 * 1024 * 1024:\n        // 16Mbit, 2MByte\n        flash_size = SIZE_16MBIT;\n        flash_set_size(flash_size);\n        break;\n    case 4 * 1024 * 1024:\n        // 32Mbit, 4MByte\n        flash_size = SIZE_32MBIT;\n        flash_set_size(flash_size);\n        break;\n    default:\n        // Unknown flash size.\n        result = false;\n        break;\n    }\n    return result;\n}\n\nuint16_t flash_get_sec_num(void)\n{\n    return flash_get_size_byte() / SPI_FLASH_SEC_SIZE;\n}\n\nuint8_t flash_get_mode(void)\n{\n    SPIFlashInfo spi_flash_info = flash_get_info();\n    switch (spi_flash_info.mode)\n    {\n    // Reserved for future use\n    case MODE_QIO:\n        break;\n    case MODE_QOUT:\n        break;\n    case MODE_DIO:\n        break;\n    case MODE_DOUT:\n        break;\n    }\n    return spi_flash_info.mode;\n}\n\nuint32_t flash_get_speed(void)\n{\n    uint32_t speed = 0;\n    SPIFlashInfo spi_flash_info = flash_get_info();\n    switch (spi_flash_info.speed)\n    {\n    case SPEED_40MHZ:\n        // 40MHz\n        speed = 40000000;\n        break;\n    case SPEED_26MHZ:\n        //26.7MHz\n        speed = 26700000;\n        break;\n    case SPEED_20MHZ:\n        // 20MHz\n        speed = 20000000;\n        break;\n    case SPEED_80MHZ:\n        //80MHz\n        speed = 80000000;\n        break;\n    }\n    return speed;\n}\n\nbool flash_init_data_written(void)\n{\n    // FLASH SEC - 4\n    uint32_t data[2] ICACHE_STORE_ATTR;\n    if (SPI_FLASH_RESULT_OK == spi_flash_read((flash_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)data, sizeof(data)))\n    {\n        if (data[0] == 0xFFFFFFFF && data[1] == 0xFFFFFFFF)\n        {\n            return false;\n        }\n    }\n    return true;\n}\n\nbool flash_init_data_default(void)\n{\n    // FLASH SEC - 4\n    // Dangerous, here are dinosaur infested!!!!!\n    // Reboot required!!!\n    // It will init system data to default!\n    bool result = false;\n    if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 4)))\n    {\n        if (SPI_FLASH_RESULT_OK == spi_flash_write((flash_get_sec_num() - 4) * SPI_FLASH_SEC_SIZE, (uint32 *)flash_init_data, 128))\n        {\n            result = true;\n        }\n    }\n    return result;\n}\n\nbool flash_init_data_blank(void)\n{\n    // FLASH SEC - 2\n    // Dangerous, here are dinosaur infested!!!!!\n    // Reboot required!!!\n    // It will init system config to blank!\n    bool result = false;\n    if ((SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 2))) &&\n            (SPI_FLASH_RESULT_OK == spi_flash_erase_sector((flash_get_sec_num() - 1))))\n    {\n        result = true;\n    }\n\n    return result ;\n}\n\nbool flash_self_destruct(void)\n{\n    // Dangerous, Erase your flash. Good bye!\n    SPIEraseChip();\n    return true;\n}\n\nuint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index)\n{\n    if( (((uint32_t)aligned_array)%4) != 0 ){\n        //NODE_DBG(\"aligned_array is not 4-byte aligned.\");\n        return 0;\n    }\n    uint32_t v = ((uint32_t *)aligned_array)[ index/4 ];\n    uint8_t *p = (uint8_t *) (&v);\n    return p[ (index%4) ];\n}\n"
  },
  {
    "path": "app/platform/flash_api.h",
    "content": "#ifndef __FLASH_API_H__\n#define __FLASH_API_H__\n#include \"ets_sys.h\"\n#include \"user_config.h\"\n#include \"cpu_esp8266.h\"\n#define FLASH_MAP_START_ADDRESS (INTERNAL_FLASH_START_ADDRESS)\n\n/******************************************************************************\n * ROM Function definition\n * Note: It is unsafe to use ROM function, but it may efficient.\n * SPIEraseSector\n * unknown SPIEraseSector(uint16 sec);\n * The 1st parameter is flash sector number.\n\n * SPIRead (Unsafe)\n * unknown SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size);\n * The 1st parameter is source addresses.\n * The 2nd parameter is destination addresses.\n * The 3rd parameter is size.\n * Note: Sometimes it have no effect, may be need a delay or other option(lock or unlock, etc.) with known reason.\n\n * SPIWrite (Unsafe)\n * unknown SPIWrite(uint32_t des_addr, uint32_t *src_addr, uint32_t size);\n * The 1st parameter is destination addresses.\n * The 2nd parameter is source addresses.\n * The 3rd parameter is size.\n * Note: Sometimes it have no effect, may be need a delay or other option(lock or unlock, etc.) with known reason.\n*******************************************************************************/\n\ntypedef struct\n{\n    uint8_t unknown0;\n    uint8_t unknown1;\n    enum\n    {\n        MODE_QIO = 0,\n        MODE_QOUT = 1,\n        MODE_DIO = 2,\n        MODE_DOUT = 15,\n    } mode : 8;\n    enum\n    {\n        SPEED_40MHZ = 0,\n        SPEED_26MHZ = 1,\n        SPEED_20MHZ = 2,\n        SPEED_80MHZ = 15,\n    } speed : 4;\n    enum\n    {\n        SIZE_4MBIT = 0,\n        SIZE_2MBIT = 1,\n        SIZE_8MBIT = 2,\n        SIZE_16MBIT = 3,\n        SIZE_32MBIT = 4,\n    } size : 4;\n} ICACHE_STORE_TYPEDEF_ATTR SPIFlashInfo;\n\nSPIFlashInfo flash_get_info(void);\nuint8_t flash_get_size(void);\nuint32_t flash_get_size_byte(void);\nbool flash_set_size(uint8_t);\nbool flash_set_size_byte(uint32_t);\nuint16_t flash_get_sec_num(void);\nuint8_t flash_get_mode(void);\nuint32_t flash_get_speed(void);\nbool flash_init_data_written(void);\nbool flash_init_data_default(void);\nbool flash_init_data_blank(void);\nbool flash_self_destruct(void);\nuint8_t byte_of_aligned_array(const uint8_t* aligned_array, uint32_t index);\n\n#endif // __FLASH_API_H__\n"
  },
  {
    "path": "app/platform/flash_fs.c",
    "content": "#include \"flash_fs.h\"\n#include \"c_string.h\"\n\n#if defined( BUILD_WOFS )\n#include \"romfs.h\"\n#elif defined( BUILD_SPIFFS )\n#include \"spiffs.h\"\n#endif\n\nint fs_mode2flag(const char *mode){\n  if(c_strlen(mode)==1){\n  \tif(c_strcmp(mode,\"w\")==0)\n  \t  return FS_WRONLY|FS_CREAT|FS_TRUNC;\n  \telse if(c_strcmp(mode, \"r\")==0)\n  \t  return FS_RDONLY;\n  \telse if(c_strcmp(mode, \"a\")==0)\n  \t  return FS_WRONLY|FS_CREAT|FS_APPEND;\n  \telse\n  \t  return FS_RDONLY;\n  } else if (c_strlen(mode)==2){\n  \tif(c_strcmp(mode,\"r+\")==0)\n  \t  return FS_RDWR;\n  \telse if(c_strcmp(mode, \"w+\")==0)\n  \t  return FS_RDWR|FS_CREAT|FS_TRUNC;\n  \telse if(c_strcmp(mode, \"a+\")==0)\n  \t  return FS_RDWR|FS_CREAT|FS_APPEND;\n  \telse\n  \t  return FS_RDONLY;\n  } else {\n  \treturn FS_RDONLY;\n  }\n}\n"
  },
  {
    "path": "app/platform/flash_fs.h",
    "content": "\n#ifndef __FLASH_FS_H__\n#define __FLASH_FS_H__\n\n#include \"user_config.h\"\n\n#if defined( BUILD_SPIFFS )\n\n#include \"spiffs.h\"\n\n#define FS_OPEN_OK\t1\n\n#define FS_RDONLY SPIFFS_RDONLY\n#define FS_WRONLY SPIFFS_WRONLY\n#define FS_RDWR SPIFFS_RDWR\n#define FS_APPEND SPIFFS_APPEND\n#define FS_TRUNC SPIFFS_TRUNC\n#define FS_CREAT SPIFFS_CREAT\n#define FS_EXCL SPIFFS_EXCL\n\n#define FS_SEEK_SET SPIFFS_SEEK_SET\n#define FS_SEEK_CUR SPIFFS_SEEK_CUR\n#define FS_SEEK_END SPIFFS_SEEK_END\n\n#define fs_open myspiffs_open\n#define fs_close myspiffs_close\n#define fs_write myspiffs_write\n#define fs_read myspiffs_read\n#define fs_seek myspiffs_lseek\n#define fs_eof myspiffs_eof\n#define fs_getc myspiffs_getc\n#define fs_ungetc myspiffs_ungetc\n#define fs_flush myspiffs_flush\n#define fs_error myspiffs_error\n#define fs_clearerr myspiffs_clearerr\n#define fs_tell myspiffs_tell\n\n#define fs_format myspiffs_format\n#define fs_check myspiffs_check\n\n#define FS_NAME_MAX_LENGTH SPIFFS_OBJ_NAME_LEN\n\n#endif\n\nint fs_mode2flag(const char *mode);\n\n#endif // #ifndef __FLASH_FS_H__\n"
  },
  {
    "path": "app/platform/pin_map.c",
    "content": "#include \"pin_map.h\"\n#include \"eagle_soc.h\"\n#if 0\nuint32_t pin_mux[GPIO_PIN_NUM] = {PERIPHS_IO_MUX_MTDI_U,  PERIPHS_IO_MUX_MTCK_U,  PERIPHS_IO_MUX_MTMS_U, \t PERIPHS_IO_MUX_MTDO_U,\n\t\t\t\t\t\t\t\t  PERIPHS_IO_MUX_U0RXD_U, PERIPHS_IO_MUX_U0TXD_U, PERIPHS_IO_MUX_SD_DATA2_U, PERIPHS_IO_MUX_SD_DATA3_U,\n\t\t\t\t\t\t\t\t  PERIPHS_IO_MUX_GPIO0_U, PERIPHS_IO_MUX_GPIO2_U, PERIPHS_IO_MUX_GPIO4_U, \t PERIPHS_IO_MUX_GPIO5_U};\n\nuint8_t pin_num[GPIO_PIN_NUM] = {12, 13, 14, 15,\n\t\t\t\t\t\t\t\t  3,  1,  9, 10,\n\t\t\t\t\t\t\t\t  0,  2,  4,  5};\n\nuint8_t pin_func[GPIO_PIN_NUM] = {FUNC_GPIO12, FUNC_GPIO13, FUNC_GPIO14, FUNC_GPIO15,\n\t\t\t\t\t\t\t\t  FUNC_GPIO3,  FUNC_GPIO1,  FUNC_GPIO9,  FUNC_GPIO10,\n\t\t\t\t\t\t\t\t  FUNC_GPIO0,  FUNC_GPIO2,  FUNC_GPIO4,  FUNC_GPIO5};\n\n#ifdef GPIO_INTERRUPT_ENABLE\nGPIO_INT_TYPE pin_int_type[GPIO_PIN_NUM] = {\n\t\t\t\t\t\t\t\tGPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,\n\t\t\t\t\t\t\t\tGPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,\n\t\t\t\t\t\t\t\tGPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE};\n#endif\n#else\nuint32_t pin_mux[GPIO_PIN_NUM] = {PAD_XPD_DCDC_CONF,  PERIPHS_IO_MUX_GPIO5_U,  PERIPHS_IO_MUX_GPIO4_U, \t PERIPHS_IO_MUX_GPIO0_U,\n\t\t\t\t\t\t\t\t  PERIPHS_IO_MUX_GPIO2_U, PERIPHS_IO_MUX_MTMS_U, PERIPHS_IO_MUX_MTDI_U, PERIPHS_IO_MUX_MTCK_U,\n\t\t\t\t\t\t\t\t  PERIPHS_IO_MUX_MTDO_U, PERIPHS_IO_MUX_U0RXD_U, PERIPHS_IO_MUX_U0TXD_U, PERIPHS_IO_MUX_SD_DATA2_U,\n\t\t\t\t\t\t\t\t  PERIPHS_IO_MUX_SD_DATA3_U };\n\nuint8_t pin_num[GPIO_PIN_NUM] = {16, 5, 4, 0,\n\t\t\t\t\t\t\t\t  2,  14,  12, 13,\n\t\t\t\t\t\t\t\t  15,  3,  1, 9,\n\t\t\t\t\t\t\t\t  10};\n\nuint8_t pin_func[GPIO_PIN_NUM] = {0, FUNC_GPIO5, FUNC_GPIO4, FUNC_GPIO0,\n\t\t\t\t\t\t\t\t  FUNC_GPIO2,  FUNC_GPIO14,  FUNC_GPIO12,  FUNC_GPIO13,\n\t\t\t\t\t\t\t\t  FUNC_GPIO15,  FUNC_GPIO3,  FUNC_GPIO1, FUNC_GPIO9,\n\t\t\t\t\t\t\t\t  FUNC_GPIO10};\n\n#ifdef GPIO_INTERRUPT_ENABLE\nGPIO_INT_TYPE pin_int_type[GPIO_PIN_NUM] = {\n\t\t\t\t\t\t\t\tGPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,\n\t\t\t\t\t\t\t\tGPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,\n\t\t\t\t\t\t\t\tGPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE, GPIO_PIN_INTR_DISABLE,\n\t\t\t\t\t\t\t\tGPIO_PIN_INTR_DISABLE};\n#endif\n#endif\n"
  },
  {
    "path": "app/platform/pin_map.h",
    "content": "\n#ifndef __PIN_MAP_H__\n#define __PIN_MAP_H__\n\n#include \"c_types.h\"\n#include \"user_config.h\"\n#include \"gpio.h\"\n\n#define GPIO_PIN_NUM 13\n\nextern uint8_t pin_num[GPIO_PIN_NUM];\nextern uint8_t pin_func[GPIO_PIN_NUM];\nextern uint32_t pin_mux[GPIO_PIN_NUM];\n#ifdef GPIO_INTERRUPT_ENABLE\nextern GPIO_INT_TYPE pin_int_type[GPIO_PIN_NUM];\n#endif\n#endif // #ifndef __PIN_MAP_H__\n"
  },
  {
    "path": "app/platform/platform.c",
    "content": "// Platform-dependent functions\n\n#include \"platform.h\"\n#include \"c_stdio.h\"\n#include \"c_string.h\"\n#include \"c_stdlib.h\"\n#include \"gpio.h\"\n#include \"user_interface.h\"\n#include \"driver/uart.h\"\n// Platform specific includes\n\nstatic void pwms_init();\n\n\nvoid output_redirect(const char *str){\n\n  #ifdef DEVELOP_VERSION    \n     uart_write_string(0,str);\n  #endif\n}\n\nint platform_init()\n{\n  // Setup PWMs\n  pwms_init();\n\n  cmn_platform_init();\n  // All done\n  return PLATFORM_OK;\n}\n\n// ****************************************************************************\n// KEY_LED functions\nuint8_t platform_key_led( uint8_t level){\n  uint8_t temp;\n  gpio16_output_set(1);   // set to high first, for reading key low level\n  gpio16_input_conf();\n  temp = gpio16_input_get();\n  gpio16_output_conf();\n  gpio16_output_set(level);\n  return temp;\n}\n\n// ****************************************************************************\n// GPIO functions\nint platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull )\n{\n  // NODE_DBG(\"Function platform_gpio_mode() is called. pin_mux:%d, func:%d\",pin_mux[pin],pin_func[pin]);\n  if (pin >= NUM_GPIO)\n    return -1;\n  if(pin == 0){\n    if(mode==PLATFORM_GPIO_INPUT)\n      gpio16_input_conf();\n    else\n      gpio16_output_conf();\n    return 1;\n  }\n\n  platform_pwm_close(pin);    // closed from pwm module, if it is used in pwm\n\n  switch(pull){\n    case PLATFORM_GPIO_PULLUP:\n      PIN_PULLDWN_DIS(pin_mux[pin]);\n      PIN_PULLUP_EN(pin_mux[pin]);\n      break;\n    case PLATFORM_GPIO_PULLDOWN:\n      PIN_PULLUP_DIS(pin_mux[pin]);\n      PIN_PULLDWN_EN(pin_mux[pin]);\n      break;\n    case PLATFORM_GPIO_FLOAT:\n      PIN_PULLUP_DIS(pin_mux[pin]);\n      PIN_PULLDWN_DIS(pin_mux[pin]);\n      break;\n    default:\n      PIN_PULLUP_DIS(pin_mux[pin]);\n      PIN_PULLDWN_DIS(pin_mux[pin]);\n      break;\n  }\n\n  switch(mode){\n    case PLATFORM_GPIO_INPUT:\n#ifdef GPIO_INTERRUPT_ENABLE\n      //lua_gpio_unref(pin);    // unref the lua ref call back.\n#endif\n      GPIO_DIS_OUTPUT(pin_num[pin]);\n    case PLATFORM_GPIO_OUTPUT:\n      ETS_GPIO_INTR_DISABLE();\n#ifdef GPIO_INTERRUPT_ENABLE\n      pin_int_type[pin] = GPIO_PIN_INTR_DISABLE;\n#endif\n      PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]);\n      //disable interrupt\n      gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), GPIO_PIN_INTR_DISABLE);\n      //clear interrupt status\n      GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));\n      GPIO_REG_WRITE(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin])), GPIO_REG_READ(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin]))) & (~ GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE))); //disable open drain; \n      ETS_GPIO_INTR_ENABLE();\n      break;\n#ifdef GPIO_INTERRUPT_ENABLE\n    case PLATFORM_GPIO_INT:\n      ETS_GPIO_INTR_DISABLE();\n      PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]);\n      GPIO_DIS_OUTPUT(pin_num[pin]);\n      gpio_register_set(GPIO_PIN_ADDR(GPIO_ID_PIN(pin_num[pin])), GPIO_PIN_INT_TYPE_SET(GPIO_PIN_INTR_DISABLE)\n                        | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_DISABLE)\n                        | GPIO_PIN_SOURCE_SET(GPIO_AS_PIN_SOURCE));\n      ETS_GPIO_INTR_ENABLE();\n      break;\n#endif\n    default:\n      break;\n  }\n  return 1;\n}\n\nint platform_gpio_write( unsigned pin, unsigned level )\n{\n  // NODE_DBG(\"Function platform_gpio_write() is called. pin:%d, level:%d\",GPIO_ID_PIN(pin_num[pin]),level);\n  if (pin >= NUM_GPIO)\n    return -1;\n  if(pin == 0){\n    gpio16_output_conf();\n    gpio16_output_set(level);\n    return 1;\n  }\n\n  GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), level);\n}\n\nint platform_gpio_read( unsigned pin )\n{\n  // NODE_DBG(\"Function platform_gpio_read() is called. pin:%d\",GPIO_ID_PIN(pin_num[pin]));\n  if (pin >= NUM_GPIO)\n    return -1;\n\n  if(pin == 0){\n    // gpio16_input_conf();\n    return 0x1 & gpio16_input_get();\n  }\n\n  // GPIO_DIS_OUTPUT(pin_num[pin]);\n  return 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[pin]));\n}\n\n#ifdef GPIO_INTERRUPT_ENABLE\nstatic void platform_gpio_intr_dispatcher( platform_gpio_intr_handler_fn_t cb){\n  uint8 i, level;\n  uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);\n  for (i = 0; i < GPIO_PIN_NUM; i++) {\n    if (pin_int_type[i] && (gpio_status & BIT(pin_num[i])) ) {\n      //disable interrupt\n      gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[i]), GPIO_PIN_INTR_DISABLE);\n      //clear interrupt status\n      GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & BIT(pin_num[i]));\n      level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(pin_num[i]));\n      if(cb){\n        cb(i, level);\n      }\n      gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[i]), pin_int_type[i]);\n    }\n  }\n}\n\nvoid platform_gpio_init( platform_gpio_intr_handler_fn_t cb )\n{\n  ETS_GPIO_INTR_ATTACH(platform_gpio_intr_dispatcher, cb);\n}\n\nint platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type )\n{\n  if (pin >= NUM_GPIO)\n    return -1;\n  ETS_GPIO_INTR_DISABLE();\n  //clear interrupt status\n  GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(pin_num[pin]));\n  pin_int_type[pin] = type;\n  //enable interrupt\n  gpio_pin_intr_state_set(GPIO_ID_PIN(pin_num[pin]), type);\n  ETS_GPIO_INTR_ENABLE();\n}\n#endif\n\n// ****************************************************************************\n// UART\n// TODO: Support timeouts.\n\n\n\n// Send: version with and without mux\nvoid platform_uart_send( unsigned id, u8 data ) \n{\n  uart_write_char(id, data);\n}\n\n// ****************************************************************************\n// PWMs\n\nstatic uint16_t pwms_duty[NUM_PWM] = {0};\n\nstatic void pwms_init()\n{\n  int i;\n  for(i=0;i<NUM_PWM;i++){\n    pwms_duty[i] = DUTY(0);\n  }\n  pwm_init(500, NULL);\n  // NODE_DBG(\"Function pwms_init() is called.\");\n}\n\n// Return the PWM clock\n// NOTE: Can't find a function to query for the period set for the timer,\n// therefore using the struct.\n// This may require adjustment if driver libraries are updated.\nuint32_t platform_pwm_get_clock( unsigned pin )\n{\n  // NODE_DBG(\"Function platform_pwm_get_clock() is called.\");\n  if( pin >= NUM_PWM)\n    return 0;\n  if(!pwm_exist(pin))\n    return 0;\n\n  return (uint32_t)pwm_get_freq(pin);\n}\n\n// Set the PWM clock\nuint32_t platform_pwm_set_clock( unsigned pin, uint32_t clock )\n{\n  // NODE_DBG(\"Function platform_pwm_set_clock() is called.\");\n  if( pin >= NUM_PWM)\n    return 0;\n  if(!pwm_exist(pin))\n    return 0;\n\n  pwm_set_freq((uint16_t)clock, pin);\n  pwm_start();\n  return (uint32_t)pwm_get_freq( pin );\n}\n\nuint32_t platform_pwm_get_duty( unsigned pin )\n{\n  // NODE_DBG(\"Function platform_pwm_get_duty() is called.\");\n  if( pin < NUM_PWM){\n    if(!pwm_exist(pin))\n      return 0;\n    // return NORMAL_DUTY(pwm_get_duty(pin));\n    return pwms_duty[pin];\n  }\n  return 0;\n}\n\n// Set the PWM duty\nuint32_t platform_pwm_set_duty( unsigned pin, uint32_t duty )\n{\n  // NODE_DBG(\"Function platform_pwm_set_duty() is called.\");\n  if ( pin < NUM_PWM)\n  {\n    if(!pwm_exist(pin))\n      return 0;\n    pwm_set_duty(DUTY(duty), pin);\n  } else {\n    return 0;\n  }\n  pwm_start();\n  pwms_duty[pin] = NORMAL_DUTY(pwm_get_duty(pin));\n  return pwms_duty[pin];\n}\n\nuint32_t platform_pwm_setup( unsigned pin, uint32_t frequency, unsigned duty )\n{\n  uint32_t clock;\n  if ( pin < NUM_PWM)\n  {\n    platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);  // disable gpio interrupt first\n    if(!pwm_add(pin)) \n      return 0;\n    // pwm_set_duty(DUTY(duty), pin);\n    pwm_set_duty(0, pin);\n    pwms_duty[pin] = duty;\n    pwm_set_freq((uint16_t)frequency, pin);\n  } else {\n    return 0;\n  }\n  clock = platform_pwm_get_clock( pin );\n  pwm_start();\n  return clock;\n}\n\nvoid platform_pwm_close( unsigned pin )\n{\n  // NODE_DBG(\"Function platform_pwm_stop() is called.\");\n  if ( pin < NUM_PWM)\n  {\n    pwm_delete(pin);\n    pwm_start();\n  }\n}\n\nvoid platform_pwm_start( unsigned pin )\n{\n  // NODE_DBG(\"Function platform_pwm_start() is called.\");\n  if ( pin < NUM_PWM)\n  {\n    if(!pwm_exist(pin))\n      return;\n    pwm_set_duty(DUTY(pwms_duty[pin]), pin);\n    pwm_start();\n  }\n}\n\nvoid platform_pwm_stop( unsigned pin )\n{\n  // NODE_DBG(\"Function platform_pwm_stop() is called.\");\n  if ( pin < NUM_PWM)\n  {\n    if(!pwm_exist(pin))\n      return;\n    pwm_set_duty(0, pin);\n    pwm_start();\n  }\n}\n\n// *****************************************************************************\n// I2C platform interface\n\nuint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t speed ){\n  if (sda >= NUM_GPIO || scl >= NUM_GPIO)\n    return 0;\n\n  // platform_pwm_close(sda);\n  // platform_pwm_close(scl);\n  \n  // disable gpio interrupt first\n  platform_gpio_mode(sda, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP);   // inside this func call platform_pwm_close\n  platform_gpio_mode(scl, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP);    // disable gpio interrupt first\n\n  i2c_master_gpio_init(sda, scl);\n  return PLATFORM_I2C_SPEED_SLOW;\n}\n\nvoid platform_i2c_send_start( unsigned id ){\n  i2c_master_start();\n}\n\nvoid platform_i2c_send_stop( unsigned id ){\n  i2c_master_stop();\n}\n\nint platform_i2c_send_address( unsigned id, uint16_t address, int direction ){\n  // Convert enum codes to R/w bit value.\n  // If TX == 0 and RX == 1, this test will be removed by the compiler\n  if ( ! ( PLATFORM_I2C_DIRECTION_TRANSMITTER == 0 &&\n           PLATFORM_I2C_DIRECTION_RECEIVER == 1 ) ) {\n    direction = ( direction == PLATFORM_I2C_DIRECTION_TRANSMITTER ) ? 0 : 1;\n  }\n\n  i2c_master_writeByte( (uint8_t) ((address << 1) | direction ));\n  // Low-level returns nack (0=acked); we return ack (1=acked).\n  return ! i2c_master_getAck();\n}\n\nint platform_i2c_send_byte( unsigned id, uint8_t data ){\n  i2c_master_writeByte(data);\n  // Low-level returns nack (0=acked); we return ack (1=acked).\n  return ! i2c_master_getAck();\n}\n\nint platform_i2c_recv_byte( unsigned id, int ack ){\n  uint8_t r = i2c_master_readByte();\n  i2c_master_setAck( !ack );\n  return r;\n}\n\n// *****************************************************************************\n// SPI platform interface\nuint32_t platform_spi_setup( unsigned id, int mode, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock)\n{\n  spi_master_init(id, cpol, cpha, databits, clock);\n  return 1;\n}\n\nspi_data_type platform_spi_send_recv( unsigned id, spi_data_type data )\n{\n  spi_mast_byte_write(id, &data);\n  return data;\n}\n\n// ****************************************************************************\n// Flash access functions\n\nuint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t size )\n{\n  toaddr -= INTERNAL_FLASH_START_ADDRESS;\n  SpiFlashOpResult r;\n  const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1;\n  uint32_t *apbuf = NULL;\n  if( ((uint32_t)from) & blkmask ){\n    apbuf = (uint32_t *)c_malloc(size);\n    if(!apbuf)\n      return 0;\n    c_memcpy(apbuf, from, size);\n  }\n  WRITE_PERI_REG(0x60000914, 0x73);\n  r = flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size);\n  if(apbuf)\n    c_free(apbuf);\n  if(SPI_FLASH_RESULT_OK == r)\n    return size;\n  else{\n    NODE_ERR( \"ERROR in flash_write: r=%d at %08X\\n\", ( int )r, ( unsigned )toaddr+INTERNAL_FLASH_START_ADDRESS );\n    return 0;\n  }\n}\n\nuint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size )\n{\n  fromaddr -= INTERNAL_FLASH_START_ADDRESS;\n  SpiFlashOpResult r;\n  WRITE_PERI_REG(0x60000914, 0x73);\n  r = flash_read(fromaddr, (uint32 *)to, size);\n  if(SPI_FLASH_RESULT_OK == r)\n    return size;\n  else{\n    NODE_ERR( \"ERROR in flash_read: r=%d at %08X\\n\", ( int )r, ( unsigned )fromaddr+INTERNAL_FLASH_START_ADDRESS );\n    return 0;\n  }\n}\n\nint platform_flash_erase_sector( uint32_t sector_id )\n{\n  WRITE_PERI_REG(0x60000914, 0x73);\n  return flash_erase( sector_id ) == SPI_FLASH_RESULT_OK ? PLATFORM_OK : PLATFORM_ERR;\n}\n"
  },
  {
    "path": "app/platform/platform.h",
    "content": "// Platform-specific functions\n\n#ifndef __PLATFORM_H__\n#define __PLATFORM_H__\n\n#include \"cpu_esp8266.h\"\n\n#include \"c_types.h\"\n#include \"driver/pwm.h\"\n// Error / status codes\nenum\n{\n  PLATFORM_ERR,\n  PLATFORM_OK,\n  PLATFORM_UNDERFLOW = -1\n};\n\n// Platform initialization\nint platform_init(void);\nvoid platform_int_init(void);\n\n// ****************************************************************************\n// KEY_LED functions\nuint8_t platform_key_led( uint8_t level);\n\n// *****************************************************************************\n// GPIO subsection\n#define PLATFORM_GPIO_FLOAT 0\n#define PLATFORM_GPIO_PULLUP 1\n#define PLATFORM_GPIO_PULLDOWN 2\n\n#define PLATFORM_GPIO_INT 2\n#define PLATFORM_GPIO_OUTPUT 1\n#define PLATFORM_GPIO_INPUT 0\n\n#define PLATFORM_GPIO_HIGH 1\n#define PLATFORM_GPIO_LOW 0\n\n/* GPIO interrupt handler */\ntypedef void (* platform_gpio_intr_handler_fn_t)( unsigned pin, unsigned level );\n\nint platform_gpio_mode( unsigned pin, unsigned mode, unsigned pull );\nint platform_gpio_write( unsigned pin, unsigned level );\nint platform_gpio_read( unsigned pin );\nvoid platform_gpio_init( platform_gpio_intr_handler_fn_t cb );\nint platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type );\n// *****************************************************************************\n// Timer subsection\n\n// Timer data type\ntypedef uint32_t timer_data_type;\n\n// *****************************************************************************\n// CAN subsection\n\n// Maximum length for any CAN message\n#define PLATFORM_CAN_MAXLEN                   8\n\n// eLua CAN ID types\nenum\n{\n  ELUA_CAN_ID_STD = 0,\n  ELUA_CAN_ID_EXT\n};\n\nint platform_can_exists( unsigned id );\nuint32_t platform_can_setup( unsigned id, uint32_t clock );\nint platform_can_send( unsigned id, uint32_t canid, uint8_t idtype, uint8_t len, const uint8_t *data );\nint platform_can_recv( unsigned id, uint32_t *canid, uint8_t *idtype, uint8_t *len, uint8_t *data );\n\n// *****************************************************************************\n// SPI subsection\n\n// There are 4 \"virtual\" SPI ports (SPI0...SPI3).\n#define PLATFORM_SPI_TOTAL                    4\n// TODO: PLATFORM_SPI_TOTAL is not used - figure out purpose, or remove?\n\n// SPI mode\n#define PLATFORM_SPI_MASTER                   1\n#define PLATFORM_SPI_SLAVE                    0\n// SS values\n#define PLATFORM_SPI_SELECT_ON                1\n#define PLATFORM_SPI_SELECT_OFF               0\n// SPI enable/disable\n#define PLATFORM_SPI_ENABLE                   1\n#define PLATFORM_SPI_DISABLE                  0\n// SPI clock phase\n#define PLATFORM_SPI_CPHA_LOW                 0\n#define PLATFORM_SPI_CPHA_HIGH                1\n// SPI clock polarity\n#define PLATFORM_SPI_CPOL_LOW                 0\n#define PLATFORM_SPI_CPOL_HIGH                1\n// SPI databits\n#define PLATFORM_SPI_DATABITS_8               8\n#define PLATFORM_SPI_DATABITS_16              16\n\n\n// Data types\ntypedef uint32_t spi_data_type;\n\n// The platform SPI functions\nint platform_spi_exists( unsigned id );\nuint32_t platform_spi_setup( unsigned id, int mode, unsigned cpol, unsigned cpha, unsigned databits, uint32_t clock);\nspi_data_type platform_spi_send_recv( unsigned id, spi_data_type data );\nvoid platform_spi_select( unsigned id, int is_select );\n\n// *****************************************************************************\n// UART subsection\n\n// There are 3 \"virtual\" UART ports (UART0...UART2).\n#define PLATFORM_UART_TOTAL                   3\n// TODO: PLATFORM_UART_TOTAL is not used - figure out purpose, or remove?\n// Note: Some CPUs (e.g. LM4F/TM4C) have more than 3 hardware UARTs\n\n// Parity\nenum\n{\n  PLATFORM_UART_PARITY_EVEN,\n  PLATFORM_UART_PARITY_ODD,\n  PLATFORM_UART_PARITY_NONE,\n  PLATFORM_UART_PARITY_MARK,\n  PLATFORM_UART_PARITY_SPACE\n};\n\n// Stop bits\nenum\n{\n  PLATFORM_UART_STOPBITS_1,\n  PLATFORM_UART_STOPBITS_1_5,\n  PLATFORM_UART_STOPBITS_2\n};\n\n// Flow control types (this is a bit mask, one can specify PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS )\n#define PLATFORM_UART_FLOW_NONE               0\n#define PLATFORM_UART_FLOW_RTS                1\n#define PLATFORM_UART_FLOW_CTS                2\n\n// The platform UART functions\nint platform_uart_exists( unsigned id );\nuint32_t platform_uart_setup( unsigned id, uint32_t baud, int databits, int parity, int stopbits );\nint platform_uart_set_buffer( unsigned id, unsigned size );\nvoid platform_uart_send( unsigned id, uint8_t data );\nvoid platform_s_uart_send( unsigned id, uint8_t data );\nint platform_uart_recv( unsigned id, unsigned timer_id, timer_data_type timeout );\nint platform_s_uart_recv( unsigned id, timer_data_type timeout );\nint platform_uart_set_flow_control( unsigned id, int type );\nint platform_s_uart_set_flow_control( unsigned id, int type );\n\n// *****************************************************************************\n// PWM subsection\n\n// There are 16 \"virtual\" PWM channels (PWM0...PWM15)\n#define PLATFORM_PWM_TOTAL                    16\n// TODO: PLATFORM_PWM_TOTAL is not used - figure out purpose, or remove?\n\n#define NORMAL_PWM_DEPTH  PWM_DEPTH\n#define NORMAL_DUTY(d) (((unsigned)(d)*NORMAL_PWM_DEPTH) / PWM_DEPTH)\n#define DUTY(d) ((uint16_t)( ((unsigned)(d)*PWM_DEPTH) / NORMAL_PWM_DEPTH) )\n\n// The platform PWM functions\nint platform_pwm_exists( unsigned id );\nuint32_t platform_pwm_setup( unsigned id, uint32_t frequency, unsigned duty );\nvoid platform_pwm_close( unsigned id );\nvoid platform_pwm_start( unsigned id );\nvoid platform_pwm_stop( unsigned id );\nuint32_t platform_pwm_set_clock( unsigned id, uint32_t data );\nuint32_t platform_pwm_get_clock( unsigned id );\nuint32_t platform_pwm_set_duty( unsigned id, uint32_t data );\nuint32_t platform_pwm_get_duty( unsigned id );\n\n\n// *****************************************************************************\n// The platform ADC functions\n\n// Functions requiring platform-specific implementation\nint  platform_adc_update_sequence(void);\nint  platform_adc_start_sequence(void);\nvoid platform_adc_stop( unsigned id );\nuint32_t  platform_adc_set_clock( unsigned id, uint32_t frequency);\nint  platform_adc_check_timer_id( unsigned id, unsigned timer_id );\n\n// ADC Common Functions\nint  platform_adc_exists( unsigned id );\nuint32_t  platform_adc_get_maxval( unsigned id );\nuint32_t  platform_adc_set_smoothing( unsigned id, uint32_t length );\nvoid platform_adc_set_blocking( unsigned id, uint32_t mode );\nvoid platform_adc_set_freerunning( unsigned id, uint32_t mode );\nuint32_t  platform_adc_is_done( unsigned id );\nvoid platform_adc_set_timer( unsigned id, uint32_t timer );\n\n// *****************************************************************************\n// I2C platform interface\n\n// I2C speed\nenum\n{\n  PLATFORM_I2C_SPEED_SLOW = 100000,\n  PLATFORM_I2C_SPEED_FAST = 400000\n};\n\n// I2C direction\nenum\n{\n  PLATFORM_I2C_DIRECTION_TRANSMITTER,\n  PLATFORM_I2C_DIRECTION_RECEIVER\n};\n\nint platform_i2c_exists( unsigned id );\nuint32_t platform_i2c_setup( unsigned id, uint8_t sda, uint8_t scl, uint32_t speed );\nvoid platform_i2c_send_start( unsigned id );\nvoid platform_i2c_send_stop( unsigned id );\nint platform_i2c_send_address( unsigned id, uint16_t address, int direction );\nint platform_i2c_send_byte( unsigned id, uint8_t data );\nint platform_i2c_recv_byte( unsigned id, int ack );\n\n// *****************************************************************************\n// Ethernet specific functions\n\nvoid platform_eth_send_packet( const void* src, uint32_t size );\nuint32_t platform_eth_get_packet_nb( void* buf, uint32_t maxlen );\nvoid platform_eth_force_interrupt(void);\nuint32_t platform_eth_get_elapsed_time(void);\n\n// *****************************************************************************\n// Internal flash erase/write functions\n\nuint32_t platform_flash_get_first_free_block_address( uint32_t *psect );\nuint32_t platform_flash_get_sector_of_address( uint32_t addr );\nuint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size );\nuint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size );\nuint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t size );\nuint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size );\nuint32_t platform_flash_get_num_sectors(void);\nint platform_flash_erase_sector( uint32_t sector_id );\n\n// *****************************************************************************\n// Allocator support\n\nvoid* platform_get_first_free_ram( unsigned id );\nvoid* platform_get_last_free_ram( unsigned id );\n\n#endif\n"
  },
  {
    "path": "app/sensor/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = sensors.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../libc\nINCLUDES += -I ../platform\nINCLUDES += -I ../\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/sensor/bmp180.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n\n\n#include \"c_types.h\"\n#include \"c_stdio.h\"\n#include \"ets_sys.h\"\n#include \"osapi.h\"\n#include \"mem.h\"\n#include \"gpio.h\"\n#include \"platform.h\"\n#include \"user_interface.h\"\n#include \"user_config.h\"\n\n#include \"driver/i2c_master.h\"\n#include \"bmp180.h\"\n\n#define BMP_DEBUG_ON\n\n#ifdef BMP_DEBUG_ON\n#define BMP_DEBUG NODE_DBG\n#else\n#define BMP_DEBUG\n#endif\n\n#define BMP180_SDA_PIN 3\n#define BMP180_SCL_PIN 4\n\n\n#define BMP180_ADDRESS   0xee \n#define CONVERSION_TIME 5\n#define BMP180_CTRL_REG 0xf4\n#define BMP180_DATA_REG 0xf6\n#define BMP180_VERSION_REG 0xd1\n\n#define BMP_CMD_MEASURE_TEMP       (0x2E) // Max conversion time 4.5ms\n#define BMP_CMD_MEASURE_PRESSURE_0 (0x34) // Max conversion time 4.5ms (OSS = 0)\n//#define BMP_CMD_MEASURE_PRESSURE_1 (0x74) // Max conversion time 7.5ms (OSS = 1)\n//#define BMP_CMD_MEASURE_PRESSURE_2 (0xB4) // Max conversion time 13.5ms (OSS = 2)\n//#define BMP_CMD_MEASURE_PRESSURE_3 (0xF4) // Max conversion time 25.5ms (OSS = 3)\n\nstatic struct bmp_cal_data{\n\n\tint16_t ac1;\n\tint16_t ac2;\n\tint16_t ac3;\n\tuint16_t ac4;\n\tuint16_t ac5;\n\tuint16_t ac6;\n\tint16_t b1;\n\tint16_t b2;\n\tint16_t mb;\n\tint16_t mc;\n\tint16_t md;\n\n}bmp_cal_data;\n\nstatic uint8_t bmp_init_ok=0;\n\nstatic uint8_t ICACHE_FLASH_ATTR bmp180_write_wait_ack(uint8_t byte,uint8_t start){\n\n\t//i2c start signal\n\tif(start)\n\t\ti2c_master_start();\n\n\ti2c_master_writeByte(byte); //address the bmp\n\tif(!i2c_master_checkAck()){\n\n\t\tBMP_DEBUG(\"ack fail for byte %02x\", byte);\n\t\ti2c_master_stop();\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic uint8_t ICACHE_FLASH_ATTR bmp180_read_byte_ack(uint8_t ack_level){\n\n\tuint8_t byte = i2c_master_readByte();\n\ti2c_master_setAck(ack_level);\n\ti2c_master_send_ack();\n\n\treturn byte;\n}\n\n//read 16 bits\nstatic int16_t  ICACHE_FLASH_ATTR bmp180_read_reg_16(uint8_t reg) {\n\n\t//BMP_DEBUG(\"bmp180_read_reg\");\n\n\tif(bmp180_write_wait_ack(BMP180_ADDRESS,1))\n\tif(bmp180_write_wait_ack(reg,0))\n\tif(bmp180_write_wait_ack(BMP180_ADDRESS+1,1))\n\t{\n\t\t//read bytes\n\t\tuint8_t msb = bmp180_read_byte_ack(1);\n\t\tuint8_t lsb = bmp180_read_byte_ack(0); \t\n\n\t\ti2c_master_stop();\n\n\t\tint16_t res = msb << 8;\n\t \tres += lsb;\t\n\n\t \t//BMP_DEBUG(\"\\tvalue: %08x\",res);\n\n\t  \treturn res;\t\n\t}\n\t\n\n\n\treturn 0; //if we got here means there was some error\n\n}\n\nstatic int16_t ICACHE_FLASH_ATTR bmp180_read_raw(uint8_t cmd) {\n\n\t//BMP_DEBUG(\"bmp180_read_raw\");\n\n\tif(bmp180_write_wait_ack(BMP180_ADDRESS,1))\t\n\tif(bmp180_write_wait_ack(BMP180_CTRL_REG,0))\n\tif(bmp180_write_wait_ack(cmd,0))\n\t{\n\t\t//BMP_DEBUG(\"bmp180_read_raw init ok\");\n\n\t\ti2c_master_stop();\n\t\tos_delay_us(CONVERSION_TIME*1000);\n\t\tint16_t res = bmp180_read_reg_16(BMP180_DATA_REG);\n  \t\treturn res;\n\t}\n\n  \treturn 0; //if we got here means there was some error\n}\n\n\nint ICACHE_FLASH_ATTR bmp180_read(bmp_data *data){\n\n  \tif(!bmp_init_ok)\n  \t\treturn 0;\n\n  \tint32_t UT;\n  \tuint16_t UP;\n\tint32_t B3, B5, B6;\n\tuint32_t B4, B7;\n\tint32_t X1, X2, X3;\n\tint32_t T, P;\n\n\tUT = bmp180_read_raw(BMP_CMD_MEASURE_TEMP);\n\tUP = bmp180_read_raw(BMP_CMD_MEASURE_PRESSURE_0);\n\n\t//calc temp\n\tX1 = (UT - (int32_t)bmp_cal_data.ac6) * ((int32_t)bmp_cal_data.ac5) >> 15;\n\tX2 = ((int32_t)bmp_cal_data.mc << 11) / (X1 + (int32_t)bmp_cal_data.md); \n\tB5 = X1 + X2;\n\tT  = (B5+8) >> 4;\n\t\n\t//calc pressure\n\tB6 = B5 - 4000;\n\tX1 = ((int32_t)bmp_cal_data.b2 * ((B6 * B6) >> 12)) >> 11;\n\tX2 = ((int32_t)bmp_cal_data.ac2 * B6) >> 11;\n\tX3 = X1 + X2;\n\tB3 = (((int32_t)bmp_cal_data.ac1 * 4 + X3) + 2) / 4;\n\tX1 = ((int32_t)bmp_cal_data.ac3 * B6) >> 13;\n\tX2 = ((int32_t)bmp_cal_data.b1 * ((B6 * B6) >> 12)) >> 16;\n\tX3 = ((X1 + X2) + 2) >> 2;\n\tB4 = ((uint32_t)bmp_cal_data.ac4 * (uint32_t)(X3 + 32768)) >> 15;\n\tB7 = ((uint32_t)UP - B3) * (uint32_t)(50000UL);\n\n\tif (B7 < 0x80000000) {\n\tP = (B7 * 2) / B4;\n\t} else {\n\tP = (B7 / B4) * 2;\n\t}\n\n\tX1 = (P >> 8) * (P >> 8);\n\tX1 = (X1 * 3038) >> 16;\n\tX2 = (-7357 * P) >> 16;\n\tP = P + ((X1 + X2 + (int32_t)3791) >> 4);\n\n\tdata->temp=T;\n\tdata->press=P;\n\n#ifdef BMP_DEBUG_ON\n\n\tBMP_DEBUG(\"bmp180 pressure : %d kPa\",data->press);\n\tBMP_DEBUG(\"bmp180 temperature : %d mC\",data->temp);\n\t\n\n#endif\n\n\treturn 1;\n\n\n}\n\nint ICACHE_FLASH_ATTR bmp180_init(){\n\n\tBMP_DEBUG(\"bmp180_init\");\n\n\t//setup i2c\n\ti2c_master_gpio_init(BMP180_SDA_PIN,BMP180_SCL_PIN);\n\ti2c_master_init();\n\n\tif(!bmp180_read_reg_16(BMP180_VERSION_REG))\n\t{\n\t\tBMP_DEBUG(\"failed reading bmp version\");\n\t\treturn 0;\n\t}\n\n\t//calibration data\n\tbmp_cal_data.ac1 = bmp180_read_reg_16(0xAA);\t\t\t\t \n\tbmp_cal_data.ac2 = bmp180_read_reg_16(0xAC);\n\tbmp_cal_data.ac3 = bmp180_read_reg_16(0xAE);\n\tbmp_cal_data.ac4 = bmp180_read_reg_16(0xB0);\n\tbmp_cal_data.ac5 = bmp180_read_reg_16(0xB2);\n\tbmp_cal_data.ac6 = bmp180_read_reg_16(0xB4);\n\tbmp_cal_data.b1 =  bmp180_read_reg_16(0xB6);\n\tbmp_cal_data.b2 =  bmp180_read_reg_16(0xB8);\n\tbmp_cal_data.mb =  bmp180_read_reg_16(0xBA);\n\tbmp_cal_data.mc =  bmp180_read_reg_16(0xBC);\n\tbmp_cal_data.md =  bmp180_read_reg_16(0xBE);\n\n\tbmp_init_ok=1;\n\treturn 1;\n}"
  },
  {
    "path": "app/sensor/bmp180.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __BMP180_H\n#define __BMP180_H\n\ntypedef struct {\n\tint32_t temp;\n\tint32_t press;\n} bmp_data;\n\nint ICACHE_FLASH_ATTR bmp180_init();\nint ICACHE_FLASH_ATTR bmp180_read(bmp_data *data);\n\n#endif"
  },
  {
    "path": "app/sensor/dht22.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"ets_sys.h\"\n#include \"osapi.h\"\n#include \"c_stdio.h\"\n#include \"mem.h\"\n#include \"gpio.h\"\n#include \"platform.h\"\n#include \"user_interface.h\"\n#include \"user_config.h\"\n\n#include \"dht22.h\"\n\n#define DHT_DEBUG_ON\n\n#ifdef DHT_DEBUG_ON\n#define DHT_DBG NODE_DBG\n#else\n#define DHT_DBG\n#endif\n\n#define DHT_PIN 5\n\n#define delay_ms(ms) os_delay_us(1000*ms)\n\nint ICACHE_FLASH_ATTR dht22_read(dht_data *read){\n        \n    DHT_DBG(\"dht22_read\");\n       \n    //put dht pin on output mode with pullup\n    platform_gpio_mode(DHT_PIN,PLATFORM_GPIO_OUTPUT,PLATFORM_GPIO_PULLUP);\n    \n    uint64_t data;   \n    os_memset(&data,0,sizeof(uint64_t));\n\n    //init sequence\n    platform_gpio_write(DHT_PIN,1);\n    delay_ms(5);\n    platform_gpio_write(DHT_PIN,0);\n    delay_ms(1);\n    platform_gpio_write(DHT_PIN,1);\n    \n    //enable input reading\n    platform_gpio_mode(DHT_PIN,PLATFORM_GPIO_INPUT,PLATFORM_GPIO_PULLUP);\n\n    //find ACK start\n    //wait pin to drop\n    int timeout = 100;\n    while(platform_gpio_read(DHT_PIN) == 1 && timeout > 0)\n    {\n        os_delay_us(5);\n        timeout-=5;\n    }\n    if(timeout==0){\n        DHT_DBG(\"\\tACK start timeout\");\n        return 0;\n    }\n\n    //find ACK end\n    //wait pin to rise\n    timeout = 100;\n    while(platform_gpio_read(DHT_PIN) == 0 && timeout > 0)\n    {\n        os_delay_us(10);\n        timeout-=10;\n    }\n    if(timeout==0){\n        DHT_DBG(\"\\tACK end timeout\");\n       return 0;\n    }\n\n    //continue to read data\n       \n\n   while(1){\n\n        //wait pin to go low, signaling next bit\n        timeout = 200;\n        while(platform_gpio_read(DHT_PIN) == 1 && timeout > 0)\n        {\n            os_delay_us(5);\n            timeout-=5;\n        }\n        if(timeout==0){\n            //NODE_DBG(\"\\tdata signal timeout\");\n            break;\n        }\n\n        //wait start of bit    \n        timeout = 200;\n        while(platform_gpio_read(DHT_PIN) == 0 && timeout > 0)\n        {\n            os_delay_us(5);\n            timeout-=5;\n        }\n        if(timeout==0){\n            //NODE_DBG(\"\\tdata bit start timeout\");\n            break;\n        }\n\n        //mearure pulse lenght        \n        timeout = 200;\n        while(platform_gpio_read(DHT_PIN) == 1 && timeout > 0)\n        {\n            os_delay_us(5);\n            timeout-=5;\n        }\n        if(timeout==0){\n            //NODE_DBG(\"\\tdata bit read timeout\");\n            break;\n        }\n\n        int pulseWidth = 200 - timeout;\n\n        //shift data                \n        data <<= 1;\n\n        if(pulseWidth > 40)\n        {\n            //bit is 1\n            data |=1;\n        }\n        else{\n            //bit is 0\n            //nothing to do\n        }\n\n   }\n\n   //do the math\n   \n\n   float temp_p, hum_p;\n\n   uint8_t data_part[5];\n   data_part[4] = ((uint8_t*)&data)[0];\n   data_part[3] = ((uint8_t*)&data)[1];\n   data_part[2] = ((uint8_t*)&data)[2];\n   data_part[1] = ((uint8_t*)&data)[3];\n   data_part[0] = ((uint8_t*)&data)[4];\n\n   int checksum = (data_part[0] + data_part[1] + data_part[2] + data_part[3]) & 0xFF;\n    if (data_part[4] == checksum) {\n        // yay! checksum is valid \n        \n        hum_p = data_part[0] * 256 + data_part[1];\n        hum_p /= 10;\n\n        temp_p = (data_part[2] & 0x7F)* 256 + data_part[3];\n        temp_p /= 10.0;\n        if (data_part[2] & 0x80)\n            temp_p *= -1;\n       \n        read->temp = temp_p;\n        read->hum = hum_p;       \n\n#ifdef DHT_DEBUG_ON\n\n        char * buff = (char *)os_zalloc(64);\n\n        c_sprintf(buff,\"%f\",read->temp);\n        DHT_DBG(\"dht22_init temp : %s C\",buff);\n\n        os_memset(buff,0,64);\n        c_sprintf(buff,\"%f\",read->hum);\n        DHT_DBG(\"dht22_init humidity : %s %%\",buff);\n\n        os_free(buff);\n       \n#endif      \n       \n    }    \n\n    return 1;\n}\n\n\nvoid ICACHE_FLASH_ATTR dht22_init(){\n\n    DHT_DBG(\"dht22_init\");\n\n    //nothing to do actually   \n   \n\n}\n\n"
  },
  {
    "path": "app/sensor/dht22.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> and Jeroen Domburg <jeroen@spritesmods.com> \n * wrote this file. As long as you retain this notice you can do whatever you \n * want with this stuff. If we meet some day, and you think this stuff is \n * worth it, you can buy us a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __DHT22_H\n#define __DHT22_H\n\ntypedef struct{\n\n\tfloat temp;\n\tfloat hum;\n\n} dht_data;\n\n\nint ICACHE_FLASH_ATTR dht22_read(dht_data *data);\n\n#endif"
  },
  {
    "path": "app/sensor/ds18b20.c",
    "content": "// based on \"How to measure temperature with your Arduino and a DS18B20\"\n// http://www.tweaking4all.com/hardware/arduino/arduino-ds18b20-temperature-sensor/\n\n#include \"ets_sys.h\"\n#include \"osapi.h\"\n#include \"c_stdio.h\"\n#include \"mem.h\"\n#include \"platform.h\"\n#include \"user_interface.h\"\n#include \"user_config.h\"\n#include \"driver/onewire.h\"\n\n#include \"ds18b20.h\"\n\n#define DS18B20_DEBUG_ON\n\n#ifdef DS18B20_DEBUG_ON\n#define DS18B20_DBG NODE_DBG\n#else\n#define DS18B20_DBG\n#endif\n\n#define DS18B20_PIN 4\n\n#define delay_ms(ms) os_delay_us(1000*ms)\n\nstatic int gpioPin;\n\nint ICACHE_FLASH_ATTR ds18b20_read(ds18b20_data *read) {\n\tbyte i;\n\tbyte present = 0;\n\tbyte type_s;\n\tbyte data[12];\n\tbyte addr[8];\n\tbyte crc;\n\tfloat celsius;\n\t//float fahrenheit;\n\n\tDS18B20_DBG(\"Look for OneWire Devices on PIN =%d\", gpioPin);\n\n\tif (!onewire_search(gpioPin, addr)) {\n\t\tDS18B20_DBG(\"No more addresses.\");\n\t\tonewire_reset_search(gpioPin);\n\t\tdelay_ms(250);\n\t\treturn;\n\t}\n\n\tDS18B20_DBG(\"ADDRESS = %02x %02x %02x %02x %02x %02x %02x %02x\",\n\t\t\taddr[0], addr[1], addr[2], addr[3],\n\t\t\taddr[4], addr[5], addr[6], addr[7]);\n\n\t// the first ROM byte indicates which chip\n\tswitch (addr[0]) {\n\t\tcase 0x10:\n\t\t\tDS18B20_DBG(\"  Chip = DS18S20\");  // or old DS1820\n\t\t\ttype_s = 1;\n\t\t\tbreak;\n\t\tcase 0x28:\n\t\t\tDS18B20_DBG(\"  Chip = DS18B20\");\n\t\t\ttype_s = 0;\n\t\t\tbreak;\n\t\tcase 0x22:\n\t\t\tDS18B20_DBG(\"  Chip = DS1822\");\n\t\t\ttype_s = 0;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tDS18B20_DBG(\"Device is not a DS18x20 family device.\");\n\t\t\treturn;\n\t} \n\n\tonewire_reset(gpioPin);\n\tonewire_select(gpioPin, addr);\n\tonewire_write(gpioPin, 0x44, 1);\n        // start conversion, use ds.write(0x44,1) with parasite power on at the end\n\n\tdelay_ms(1000);\n\n\tpresent = onewire_reset(gpioPin);\n\tonewire_select(gpioPin, addr);\n\tonewire_write(gpioPin, 0xBE, 1);   // Read Scratchpad\n\n\t//DS18B20_DBG(\"  Present = %d\", present);\n\tfor ( i = 0; i < 9; i++) {         // we need 9 bytes\n\t\tdata[i] = onewire_read(gpioPin);\n\t\tDS18B20_DBG(\"  DATA: %02x \", data[i]);\n\t}\n\tcrc = onewire_crc8(data, 8);\n\tDS18B20_DBG(\" CRC=%d \", crc);\n\n\tif (crc != data[8]) {\n\t\tDS18B20_DBG(\"CRC is not valid!\");\n\t\treturn;\n\t}\n\n\t// Convert the data to actual temperature\n\t// because the result is a 16 bit signed integer, it should\n\t// be stored to an \"int16_t\" type, which is always 16 bits\n\t// even when compiled on a 32 bit processor.\n\tint16_t raw = (data[1] << 8) | data[0];\n\tif (type_s) {\n\t\traw = raw << 3; // 9 bit resolution default\n\t\tif (data[7] == 0x10) {\n\t\t\t// \"count remain\" gives full 12 bit resolution\n\t\t\traw = (raw & 0xFFF0) + 12 - data[6];\n\t\t}\n\t} else {\n\t\tbyte cfg = (data[4] & 0x60);\n\t\t// at lower res, the low bits are undefined, so let's zero them\n\t\tif (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms\n\t\telse if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms\n\t\telse if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms\n\t\t//// default is 12 bit resolution, 750 ms conversion time\n\t}\n\n\tcelsius = (float) raw / 16.0;\n\t//fahrenheit = celsius * 1.8 + 32.0;\n\tread->temp = celsius;\n\n\tDS18B20_DBG(\"Temperature = \");\n\n\tchar *temp_string = (char*) os_zalloc(64);\n\n\tc_sprintf(temp_string, \"%f\", read->temp);\n\tDS18B20_DBG(\"  %s Celsius\", temp_string);\n\tos_free(temp_string);\n\n\t//DS18B20_DBG(\" %2.2f Fahrenheit\", fahrenheit);\n\n\treturn 1;\n}\n\nvoid ICACHE_FLASH_ATTR ds18b20_init(uint8_t pin) {\n\tDS18B20_DBG(\"ds18b20_init\");\n\n\tgpioPin = DS18B20_PIN; // default pin\n\tif ( pin > 0 && pin < 15) gpioPin = pin;\n\tonewire_init(gpioPin);\n\n\tonewire_reset_search(gpioPin);\n}\n"
  },
  {
    "path": "app/sensor/ds18b20.h",
    "content": "#ifndef __DS18b20_H\n#define __DS18b20_H\n\ntypedef uint8_t boolean;\ntypedef uint8_t byte;\n\ntypedef struct{\n\tfloat temp;\n} ds18b20_data;\n\nint ICACHE_FLASH_ATTR ds18b20_read(ds18b20_data *data);\n\n#endif\n"
  },
  {
    "path": "app/sensor/sensors.c",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> wrote this file. As long as you retain \n * this notice you can do whatever you want with this stuff. If we meet some day, \n * and you think this stuff is worth it, you can buy me a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#include \"c_types.h\"\n#include \"c_stdio.h\"\n#include \"ets_sys.h\"\n#include \"osapi.h\"\n#include \"mem.h\"\n#include \"gpio.h\"\n#include \"platform.h\"\n#include \"user_interface.h\"\n#include \"user_config.h\"\n\n#include \"sensors.h\"\n#include \"bmp180.h\"\n#include \"dht22.h\"\n#include \"ds18b20.h\"\n\n#define DS18B20_PIN 4\n\n#define SENSOR_TASK_QUEUE_LEN 1\n#define SENSOR_TASK_PRIORITY 1\n#define SENSOR_TASK_SIG 981237\nstatic os_event_t sensor_read_task_queue[SENSOR_TASK_QUEUE_LEN];\nstatic os_timer_t sensor_read_timer;\n\nsensor_data global_sensor_data;\n\nvoid ICACHE_FLASH_ATTR sensors_get_data(sensor_data *return_data)\n{\n\t//NODE_DBG(\"sensors_get_data\");\t\n\t*return_data = global_sensor_data;\n\treturn;\n}\n\nstatic void ICACHE_FLASH_ATTR sensor_read_task(os_event_t *e){\n\n\tif(e->sig != SENSOR_TASK_SIG)\n        return; //not our signal\n\n    dht22_read(&global_sensor_data.dht22);\n    bmp180_read(&global_sensor_data.bmp180); \n\n}\n\nstatic void ICACHE_FLASH_ATTR sensor_read_timer_cb(void *arg){\n\tsystem_os_post(SENSOR_TASK_PRIORITY, SENSOR_TASK_SIG, (os_param_t) NULL );\n}\n\nvoid ICACHE_FLASH_ATTR sensors_init(){\n\n\tNODE_DBG(\"sensors_init\");\n\n\t//init data\n\tos_memset(&global_sensor_data,0,sizeof(sensor_data));\n\n\t//init sensors\n    ds18b20_init();\n    dht22_init();\n    bmp180_init(); \n\n\t//Start os task\n    system_os_task(sensor_read_task, SENSOR_TASK_PRIORITY ,sensor_read_task_queue, SENSOR_TASK_QUEUE_LEN);\n    system_os_post(SENSOR_TASK_PRIORITY, SENSOR_TASK_SIG, (os_param_t) NULL );\n\n\t//arm sensor read timer\n\tos_memset(&sensor_read_timer,0,sizeof(os_timer_t));\n\tos_timer_disarm(&sensor_read_timer);\n\tos_timer_setfn(&sensor_read_timer, (os_timer_func_t *)sensor_read_timer_cb, NULL);\n\tos_timer_arm(&sensor_read_timer, 2000, 1);\n\n}\n"
  },
  {
    "path": "app/sensor/sensors.h",
    "content": "/*\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * Israel Lot <me@israellot.com> wrote this file. As long as you retain \n * this notice you can do whatever you want with this stuff. If we meet some day, \n * and you think this stuff is worth it, you can buy me a beer in return. \n * ----------------------------------------------------------------------------\n */\n\n#ifndef __SENSORS_H\n#define __SENSORS_H\n\n#include \"bmp180.h\"\n#include \"dht22.h\"\n\ntypedef struct {\n\n\tdht_data dht22;\n\tbmp_data bmp180;\n\n} sensor_data;\n\n\nvoid ICACHE_FLASH_ATTR sensors_init();\nvoid ICACHE_FLASH_ATTR sensors_get_data(sensor_data *return_data);\n\n\n#endif"
  },
  {
    "path": "app/smart/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = smart.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../libc\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/smart/smart.c",
    "content": "#include \"c_stdio.h\"\n#include \"c_stdlib.h\"\n#include \"c_string.h\"\n#include \"user_interface.h\"\n#include \"smart.h\"\n\n#define ADDR_MAP_NUM 10\n\nstatic os_timer_t smart_timer;\n\nstatic smart_addr_map *am[ADDR_MAP_NUM];\n\nstatic smart_addr_map *matched = NULL;\n\nstatic struct station_config *sta_conf;\n\nstatic int cur_channel = 1;\n\nstatic uint8_t mode = STATION_MODE;\n\nstatic uint8_t alldone = 0;\n\n// 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000(LSB)\n// when the bit is set, means the ssid byte is got\nstatic uint8_t *got_ssid = NULL;\nstatic uint8_t *got_password = NULL;\n\nstatic uint8_t *ssid_nibble = NULL;\nstatic uint8_t *password_nibble = NULL;\n\nstatic smart_succeed succeed = NULL;\nstatic void *smart_succeed_arg = NULL;\n\nvoid smart_end();\nint smart_check(uint8_t *nibble, uint16_t len, uint8_t *dst, uint8_t *got){\n  if(len == 0) \n    return 0;\n  uint16_t dst_len = len/NIBBLE_PER_BYTE;\n  uint16_t byte_num = 0, bit_num = 0;\n  int i = 0, res = 1; // assume ok.\n  c_memset(dst,0,dst_len);\n  \n  if(NIBBLE_PER_BYTE==1){\n    for(i=0;i<len;i++){\n      byte_num = (i) / 8;\n      bit_num = (i) % 8;\n      if(0x20>nibble[i] || nibble[i]>=0x7F){ // not printable\n        NODE_DBG(\"Smart: got np byte %d:%02x\", i, nibble[i]);\n        nibble[i] = 0;\n        got[byte_num] &= ~(0x1 << bit_num);  // clear the bit\n        res = 0;  // not ok\n      } else {\n        dst[i] = nibble[i];\n      }\n    }\n    return res;\n  }\n\n  // NIBBLE_PER_BYTE == 2\n  if((len%NIBBLE_PER_BYTE) != 0){\n    // this should not happen\n    NODE_DBG(\"Smart: smart_check got odd len\");\n    return 0;\n  }\n\n  if(len == 2){\n    // only one byte\n    if(nibble[0]<=0xF && ((nibble[0]^0x1)&0xF == (nibble[1]>>4)) ){\n      dst[0] = ((nibble[0]&0xF)<<4) + (nibble[1]&0xF);\n      res = 1;\n    }else{\n      nibble[0] = 0;\n      nibble[1] = 0;\n      got[0] &= ~(0x3 << 0);  // clear the 0 bit\n      res = 0;  // not ok\n    }\n    return res;\n  }\n\n  res = 1;  // assume ok.\n  for(i=len-2;i>0;i--){\n    bool forward = ( ((nibble[i]&0xF)^((i+1)&0xF)) == (nibble[i+1]>>4) );\n    bool back = ( ((nibble[i-1]&0xF)^(i&0xF)) == (nibble[i]>>4) );\n    if(!forward || !back){ \n    // wrong forward, or wrong back, replace i-1, i and i+1, until get right back, forward\n      NODE_DBG(\"check: wf %d:%02x %02x %02x\",i,nibble[i-1],nibble[i], nibble[i+1]);\n      byte_num = (i-1) / 8;\n      bit_num = (i-1) % 8;\n      nibble[i-1] = 0;\n      got[byte_num] &= ~(0x1 << bit_num);  // clear the bit\n\n      byte_num = (i) / 8;\n      bit_num = (i) % 8;\n      nibble[i] = 0;\n      got[byte_num] &= ~(0x1 << bit_num);  // clear the bit\n\n      byte_num = (i+1) / 8;\n      bit_num = (i+1) % 8;\n      nibble[i+1] = 0;\n      got[byte_num] &= ~(0x1 << bit_num);  // clear the bit\n      res = 0;\n      return res; // once there is error, \n    }\n\n    if((i%NIBBLE_PER_BYTE) == 0) { // i == even\n      dst[i/NIBBLE_PER_BYTE] = ((nibble[i]&0xF)<<4) + (nibble[i+1]&0xF);\n    }\n  }\n\n  if(i==0){\n    dst[0] = ((nibble[0]&0xF)<<4) + (nibble[1]&0xF);\n  }\n\n  for(i=0;i<dst_len;i++){   // check for non-printable byte\n    // NODE_DBG(\"nibble %d:%02x %02x->%02x\", i, nibble[i*NIBBLE_PER_BYTE], nibble[i*NIBBLE_PER_BYTE+1], dst[i]);\n    byte_num = (i*NIBBLE_PER_BYTE) / 8;\n    bit_num = (i*NIBBLE_PER_BYTE) % 8;\n    if(0x20>dst[i] || dst[i]>=0x7F){ // not printable\n      NODE_DBG(\"Smart: got np byte %d:%02x\", i, dst[i]);\n      dst[i] = 0; // reset byte\n      nibble[i*NIBBLE_PER_BYTE] = 0;  // reset hi-nibble\n      nibble[i*NIBBLE_PER_BYTE+1] = 0;  // reset lo-nibble\n      got[byte_num] &= ~(0x3 << bit_num);  // clear the bit\n      res = 0;  // not ok\n    } \n  }\n  return res;\n}\n\nvoid detect(uint8 *buf, uint16 len){\n  uint16_t seq;\n  int16_t seq_delta = 0;\n  uint16_t byte_num = 0, bit_num = 0;\n  int16_t c = 0;\n  if( ( (buf[0]) & TYPE_SUBTYPE_MASK) != TYPE_SUBTYPE_QOS_DATA){\n    return;\n  }\n  if( (buf[1] & DS_RETRY_MASK) != NO_RETRY )\n    return;\n  if( buf[SEQ_ADDR] & 0xF != 0 )    // Fragment Number should = 0\n    return;\n  // calculate current seq number\n  seq = buf[SEQ_ADDR+1];\n  seq = seq<<4;\n  seq += buf[SEQ_ADDR]>>4;\n\n  if(!matched){     // cur_base_seq is ref to flag[0] when finding the patern\n    int i;\n    for (i = 0; i < ADDR_MAP_NUM; i++)  // for each source-dest adress pair in the map\n    {\n      if ( am[i]->flag_match_num == 0 ){  // not in the map yet\n        if ( len - am[i]->base_len == am[i]->flag[0]) // store new source-dest adress pair to the map until flag[0] is got\n        {\n          // BSSID, SA, DA, store the SA, DA\n          c_memcpy(am[i]->addr, &buf[ADDR_MATCH_START], ADDR_MATCH_LENGTH);  \n          am[i]->flag_match_num++;    // =1\n          am[i]->cur_base_seq = seq;  // assume the first seq is found\n          am[i]->base_seq_valid = 1;\n          // NODE_DBG(\"Smart: new addr pair found\");\n        }\n        break;    // break any way for the next packet to come\n      } \n      else if(0 == c_memcmp(am[i]->addr, &buf[ADDR_MATCH_START], ADDR_MATCH_LENGTH)){   // source-dest adress pair match\n        if(am[i]->base_seq_valid == 0){\n          if ( len - am[i]->base_len == am[i]->flag[0]) { // found the new flag[0]\n            // here flag_match_num is already = 1\n            am[i]->cur_base_seq = seq;\n            am[i]->base_seq_valid = 1;  // the seq number is valid now\n            // NODE_DBG(\"Smart: new base_seq found\");\n          }\n          break;  // break any way for the next packet to come\n        }\n\n        // base seq number is valid, cal the delta\n        if(seq >= am[i]->cur_base_seq){    \n          seq_delta = seq - am[i]->cur_base_seq;\n        } else {\n          seq_delta = SEQ_MAX - am[i]->cur_base_seq + seq;\n        }\n\n        if(seq_delta < 0){   // this should never happen\n          am[i]->base_seq_valid = 0;  // the seq number is not valid\n          break;\n        }\n\n        if(seq_delta == 0){   // base_seq is not valid any more\n          if ( len - am[i]->base_len != am[i]->flag[0]) { // lost the flag[0]\n            am[i]->base_seq_valid = 0;  // the seq number is not valid\n          }\n          break;  // break any way for the next packet to come\n        } \n\n        // delta is out of range, need to find the next flag[0] to start again\n        if (seq_delta>=FLAG_NUM){\n          am[i]->flag_match_num = 1;  // reset to 1\n          if ( len - am[i]->base_len == am[i]->flag[0]) { // found the new flag[0]\n            // here flag_match_num is already = 1\n            am[i]->cur_base_seq = seq;\n            am[i]->base_seq_valid = 1;  // the seq number is valid now\n          } else {\n            am[i]->base_seq_valid = 0;\n          }\n          break;    // done for this packet\n        }\n\n        // NODE_DBG(\"Smart: match_num:%d seq_delta:%d len:%d\",am[i]->flag_match_num,seq_delta,len-am[i]->base_len);\n        // seq_delta now from 1 to FLAG_NUM-1\n        // flag[] == 0 ,means skip this flag.\n        if ( (am[i]->flag_match_num==seq_delta) && \\\n          ( (am[i]->flag[am[i]->flag_match_num]==len-am[i]->base_len) || (am[i]->flag[am[i]->flag_match_num]==0) ) ){\n          am[i]->flag_match_num++;\n          if(am[i]->flag_match_num == FLAG_MATCH_NUM){  //every thing is match.\n            NODE_ERR(\"Smart: got matched sender\\n\");\n            matched = am[i];    // got the matched source-dest adress pair who is sending the udp data\n            matched->base_seq_valid = 0;  // set to 0, and start to reference to the SSID_FLAG from now on\n            os_timer_disarm(&smart_timer);  // note: may start a longer timeout\n          }\n          break;\n        }\n\n        // non match, reset, need to find next flag[0] to start again\n        am[i]->flag_match_num = 1;\n        am[i]->base_seq_valid = 0;\n        break;\n      } // non-match source-dest adress pair, continue to next pair in the map.\n    } // for loop\n    // break out, or loop done. \n    goto end;\n  } else {  // cur_base_seq is ref to SSID_FLAG when patern is alread found\n    if(0 != c_memcmp(matched->addr, &buf[ADDR_MATCH_START], ADDR_MATCH_LENGTH)){ // source-dest adress pair not match, ignore it\n      return;\n    }\n    if (matched->base_seq_valid == 0){  // SSID_FLAG seq invalid, need to find the next valid seq number\n    // base_seq not valid, find it\n      if (len - matched->base_len == SSID_FLAG){\n        matched->cur_base_seq = seq;\n        matched->base_seq_valid = 1;\n      } \n      goto end;\n    }\n\n    if(seq >= matched->cur_base_seq){\n      seq_delta = seq - matched->cur_base_seq;\n    } else {\n      seq_delta = SEQ_MAX - matched->cur_base_seq + seq;\n    }\n\n    if(seq_delta < 0){   // this should never happen\n      matched->base_seq_valid = 0;  // the seq number is not valid\n      goto end;\n    }\n\n    if(seq_delta == 0){   // base_seq is not valid any more\n      if ( len - matched->base_len != SSID_FLAG) { // lost the SSID_FLAG\n        matched->base_seq_valid = 0;  // the seq number is not valid\n      }\n      goto end;  // exit for the next packet to come\n    } \n\n    if ( seq_delta > (SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) +\\\n      1 + (SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->pwd_len) ){ \n    // delta out of the range\n      if (len - matched->base_len == SSID_FLAG){\n        matched->cur_base_seq = seq;\n        matched->base_seq_valid = 1;\n      } else {\n        matched->base_seq_valid = 0;\n      }\n      goto end;\n    }\n        \n    // delta in the range\n    if (seq_delta==1){\n      int16_t ssid_len = len - matched->base_len - L_FLAG;\n      if ( matched->ssid_len == 0 ){   // update the ssid_len\n        if ( (ssid_len <=32) && (ssid_len >0) ){\n          matched->ssid_len = ssid_len;\n          NODE_DBG(\"Smart: found the ssid_len %d\", matched->ssid_len);\n        }\n        goto end;\n      }\n      if (ssid_len != matched->ssid_len){  // ssid_len not match\n        matched->base_seq_valid = 0;\n        // note: not match, save the new one or old one? for now save the new one.\n        matched->ssid_len = ssid_len;  \n        NODE_DBG(\"Smart: ssid_len not match\");\n      } \n      goto end; // to the next packet\n    } \n\n    if( (SEP_NUM==2)&&(seq_delta==2 || seq_delta==3) ) {\n      if (len - matched->base_len != matched->flag[seq_delta-2+SEP_1_INDEX]){  // SEP not match\n        matched->base_seq_valid = 0;\n        NODE_DBG(\"Smart: SEP-L not match\");\n      }\n      goto end; // to the next packet\n    }\n\n    if( seq_delta==(SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) + 1) {\n      if (len - matched->base_len != PWD_FLAG){  // PWD_FLAG not match\n        matched->base_seq_valid = 0;\n        NODE_DBG(\"Smart: PWD_FLAG not match\");\n      }\n      goto end; // to the next packet\n    }\n        \n    if (seq_delta==(SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) + 1 + 1){\n      int16_t pwd_len = len - matched->base_len - L_FLAG;\n      if ( matched->pwd_len == 0){\n        if ( (pwd_len <=64) && (pwd_len>0)){\n          matched->pwd_len = pwd_len;\n          NODE_DBG(\"Smart: found the pwd_len %d\", matched->pwd_len);\n        }\n        goto end; // to the next packet\n      }\n      if (pwd_len != matched->pwd_len){ // pwd_len not match\n        matched->base_seq_valid = 0;\n        // note: not match, save the new one or old one? for now save the new one.\n        matched->pwd_len = pwd_len; // reset pwd_len to 0\n        NODE_DBG(\"Smart: pwd_len not match\");\n      } \n      goto end;      \n    } \n\n    if (seq_delta <= (SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) ){   // in the ssid zone\n      uint16_t it = (seq_delta-1-SEP_NUM-1) / (SEP_NUM + 1);  // the number of ssid nibble: 0~31 or 0~63\n      uint16_t m = (seq_delta-1-SEP_NUM-1) % (SEP_NUM + 1); // 0~2\n      switch(m){\n        case 0: // the ssid hi/lo-nibble itself    \n          c = (int16_t)(len - matched->base_len - C_FLAG);\n          if (c>255 || c<0){\n            matched->base_seq_valid = 0;\n            NODE_DBG(\"Smart: wrong ssid nibble\");\n            goto end;\n          }\n          byte_num = it / 8;  // 0~7\n          bit_num = it % 8;   // 0~7\n          if( (got_ssid[byte_num] & (0x1 << bit_num)) == 0){\n            got_ssid[byte_num] |= 0x1 << bit_num; // set the bit\n            ssid_nibble[it] = c;\n          }           \n          break;\n        case 1: // seperator 1\n        case 2: // seperator 2\n          if(len - matched->base_len != matched->flag[m-1+SEP_1_INDEX]){\n            NODE_DBG(\"Smart: SEP-S not match\");\n            matched->base_seq_valid = 0;\n            goto end;\n          }\n          break;\n        default:\n          break;\n      }\n    } else {  // in the pwd zone\n      uint16_t it = (seq_delta -1 -(SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) - 2 - SEP_NUM) / (SEP_NUM + 1); // the number of pwd byte\n      uint16_t m = (seq_delta -1 -(SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) - 2 - SEP_NUM) % (SEP_NUM + 1);\n      switch(m){\n        case 0: // the pwd hi/lo-nibble itself\n          c = (int16_t)(len - matched->base_len - C_FLAG);\n          if (c>255 || c<0){\n            matched->base_seq_valid = 0;\n            NODE_DBG(\"Smart: wrong password nibble\");\n            goto end;\n          }\n          byte_num = it / 8;  // 0~15 / 7\n          bit_num = it % 8;   // 0~7\n          if( (got_password[byte_num] & (0x1 << bit_num)) == 0){\n            got_password[byte_num] |= 0x1 << bit_num; // set the bit\n            password_nibble[it] = c;\n          } \n          break;\n        case 1: // seperator 1\n        case 2: // seperator 2\n          if(len - matched->base_len != matched->flag[m-1+SEP_1_INDEX]){\n            NODE_DBG(\"Smart: SEP-P not match\");\n            matched->base_seq_valid = 0;\n            goto end;\n          }\n          break;\n        default:\n          break;\n      }\n    }\n    // check if all done\n    // NODE_DBG(\"Smart: ssid got %02x %02x\", got_ssid[0], got_ssid[1]);\n    // NODE_DBG(\"Smart: password got %02x %02x %02x\", got_password[0], got_password[1], got_password[2]);\n    int i,j;\n    for(i=0;i<NIBBLE_PER_BYTE*matched->ssid_len;i++){\n      byte_num = (i) / 8;\n      bit_num = (i) % 8;\n      if( (got_ssid[byte_num] & (0x1 << bit_num) ) != (0x1 << bit_num) ){ // check the bit == 1\n        break;\n      }\n    }\n    for(j=0;j<NIBBLE_PER_BYTE*matched->pwd_len;j++){\n      byte_num = (j) / 8;\n      bit_num = (j) % 8;\n      if( (got_password[byte_num] & (0x1 << bit_num) ) != (0x1 << bit_num) ){ // check the 2 bit == 11\n        break;\n      }\n    }\n    if(matched->ssid_len > 0 && matched->pwd_len > 0 && i==NIBBLE_PER_BYTE*matched->ssid_len && j==NIBBLE_PER_BYTE*matched->pwd_len){    // get everything, check it.\n      if( smart_check(ssid_nibble, NIBBLE_PER_BYTE*matched->ssid_len, sta_conf->ssid, got_ssid) && \\\n        smart_check(password_nibble, NIBBLE_PER_BYTE*matched->pwd_len, sta_conf->password, got_password) ){\n        // all done\n        alldone = 1;\n        NODE_ERR(sta_conf->ssid);\n        NODE_ERR(\" %d\\n\", matched->ssid_len);\n        NODE_ERR(sta_conf->password);\n        NODE_ERR(\" %d\\n\", matched->pwd_len);\n        smart_end();\n        // if(succeed){\n        //   succeed(smart_succeed_arg);\n        //   succeed = NULL; // reset to NULL when succeed\n        //   smart_succeed_arg = NULL;\n        // }\n        return;\n      }\n    }\n  }\n\nend:\n#if 0\n  NODE_DBG(\"%d:\\t0x%x 0x%x\\t\", len-BASE_LENGTH, buf[0],buf[1]);\n  NODE_DBG(MACSTR, MAC2STR(&(buf[BSSID_ADDR])));\n  NODE_DBG(\"\\t\");\n  NODE_DBG(MACSTR, MAC2STR(&(buf[SOURCE_ADDR])));\n  NODE_DBG(\"\\t\");\n  NODE_DBG(MACSTR, MAC2STR(&(buf[DEST_ADDR])));\n  uint16_t tseq = buf[SEQ_ADDR+1];\n  tseq = tseq<<4;\n  tseq += buf[SEQ_ADDR]>>4;\n  NODE_DBG(\"\\t0x%04x\", tseq);\n#endif\n  return;\n}\n\nvoid reset_map(smart_addr_map **am, size_t num){\n  int i;\n  for (i = 0; i < num; ++i)\n  {\n    am[i]->flag_match_num = 0;\n    am[i]->addr_len = ADDR_MATCH_LENGTH;\n    am[i]->base_len = BASE_LENGTH;\n    am[i]->cur_base_seq = -1;\n    am[i]->base_seq_valid = 0;\n    am[i]->ssid_len = 0;\n    am[i]->pwd_len = 0;\n    c_memset(am[i]->addr, 0, ADDR_MATCH_LENGTH);\n    if(SEP_1_INDEX==0){\n      am[i]->flag[0] = SEP_1;\n      am[i]->flag[1] = SEP_2;\n      am[i]->flag[2] = SSID_FLAG;\n    }\n    if(SEP_1_INDEX==2){\n      am[i]->flag[0] = SSID_FLAG;\n      am[i]->flag[1] = 0; // skip this flag\n      am[i]->flag[2] = SEP_1;     \n      am[i]->flag[3] = SEP_2;      \n    }\n  }\n}\n\nvoid smart_enable(void){\n  wifi_promiscuous_enable(1); \n}\n\nvoid smart_disable(void){\n  wifi_promiscuous_enable(0); \n}\n\nvoid smart_end(){\n  int i;\n  os_timer_disarm(&smart_timer);\n  smart_disable();\n  wifi_set_channel(cur_channel);\n\n  if(NULL_MODE != mode){\n    wifi_set_opmode(mode);\n  } else {\n    wifi_set_opmode(STATION_MODE);\n  }\n  \n  mode = wifi_get_opmode();\n\n  if(sta_conf && alldone){\n    if( (STATION_MODE == mode) || (mode == STATIONAP_MODE) ){\n      wifi_station_set_config(sta_conf);\n      wifi_station_set_auto_connect(true);\n      wifi_station_disconnect();\n      wifi_station_connect();\n\n      os_timer_disarm(&smart_timer);\n      os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, 1);\n      os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0);   // no repeat\n    }\n  }\n\n  for (i = 0; i < ADDR_MAP_NUM; ++i)\n  {\n    if(am[i]){\n      c_free(am[i]);\n      am[i] = NULL;\n    }\n    matched = NULL;\n  }  \n\n  if(sta_conf){\n    c_free(sta_conf);\n    sta_conf = NULL;\n  }\n\n  if(got_password){\n    c_free(got_password);\n    got_password = NULL;\n  }\n\n  if(got_ssid){\n    c_free(got_ssid);\n    got_ssid = NULL;\n  }\n\n  if(password_nibble){\n    c_free(password_nibble);\n    password_nibble = NULL;\n  }\n\n  if(ssid_nibble){\n    c_free(ssid_nibble);\n    ssid_nibble = NULL;\n  }\n  // system_restart();   // restart to enable the mode\n}\n\nvoid smart_next_channel(){\n  smart_disable();\n  switch(cur_channel){\n    case 1:\n      cur_channel = MAX_CHANNEL;\n      break;\n    case 2:\n    case 3:\n    case 4:\n      cur_channel++;\n      break;\n    case 5:\n      cur_channel = 7;\n      break;\n    case 6:\n      cur_channel = 1;\n      break;\n    case 7:\n    case 8:\n    case 9:\n    case 10:\n    case 11:\n    case 12:\n      cur_channel++;\n      break;\n    case 13:\n      cur_channel = 6;\n      break;\n    case MAX_CHANNEL:\n      cur_channel = 2;\n      break;\n    default:\n      cur_channel = 6;\n      break;\n  }\n\n  NODE_ERR(\"switch to channel %d\\n\", cur_channel);\n  wifi_set_channel(cur_channel);\n  reset_map(am, ADDR_MAP_NUM);\n  c_memset(sta_conf->ssid, 0, sizeof(sta_conf->ssid));\n  c_memset(sta_conf->password, 0, sizeof(sta_conf->password));\n\n  c_memset(got_ssid, 0, SSID_BIT_MAX);\n  c_memset(got_password, 0, PWD_BIT_MAX);\n\n  c_memset(ssid_nibble, 0, SSID_NIBBLE_MAX);\n  c_memset(password_nibble, 0, PWD_NIBBLE_MAX);\n\n  os_timer_disarm(&smart_timer);\n  os_timer_arm(&smart_timer, TIME_OUT_PER_CHANNEL, 0);   // no repeat\n\n  smart_enable();\n}\n\nvoid smart_begin(int chnl, smart_succeed s, void *arg){\n  int i;\n  alldone = 0;\n  for (i = 0; i < ADDR_MAP_NUM; ++i)\n  {\n    if(!am[i]){\n      am[i] = (smart_addr_map*)c_zalloc(sizeof(smart_addr_map));\n      if(!am[i]){\n        NODE_DBG(\"smart_begin map no memory\");\n        smart_end();\n        return;\n      }\n    }\n  }\n  if(!sta_conf){\n    sta_conf = (struct station_config *)c_zalloc(sizeof(struct station_config));\n    if(!sta_conf){\n      NODE_DBG(\"smart_begin sta_conf no memory\");\n      smart_end();\n      return;\n    }\n  }\n\n  if(!ssid_nibble){\n    ssid_nibble = (uint8_t *)c_zalloc(SSID_NIBBLE_MAX);\n    if(!ssid_nibble){\n      NODE_DBG(\"smart_begin sta_conf no memory\");\n      smart_end();\n      return;\n    }\n  }\n\n  if(!password_nibble){\n    password_nibble = (uint8_t *)c_zalloc(PWD_NIBBLE_MAX);\n    if(!password_nibble){\n      NODE_DBG(\"smart_begin sta_conf no memory\");\n      smart_end();\n      return;\n    }\n  }\n\n  if(!got_ssid){\n    got_ssid = (uint8_t *)c_zalloc(SSID_BIT_MAX);\n    if(!got_ssid){\n      NODE_DBG(\"smart_begin sta_conf no memory\");\n      smart_end();\n      return;\n    }\n  }\n\n  if(!got_password){\n    got_password = (uint8_t *)c_zalloc(PWD_BIT_MAX);\n    if(!got_password){\n      NODE_DBG(\"smart_begin sta_conf no memory\");\n      smart_end();\n      return;\n    }\n  }\n  reset_map(am, ADDR_MAP_NUM);\n  // c_memset(sta_conf->ssid, 0, sizeof(sta_conf->ssid));\n  // c_memset(sta_conf->password, 0, sizeof(sta_conf->password));\n\n  // c_memset(got_ssid, 0, SSID_BIT_MAX);\n  // c_memset(got_password, 0, PWD_BIT_MAX);\n\n  // c_memset(ssid_nibble, 0, SSID_NIBBLE_MAX);\n  // c_memset(password_nibble, 0, PWD_NIBBLE_MAX);\n  mode = wifi_get_opmode();\n  if( (STATION_MODE == mode) || (mode == STATIONAP_MODE) ){\n    wifi_station_set_auto_connect(false);\n    wifi_station_disconnect();\n  }\n  cur_channel = chnl;\n  NODE_ERR(\"set channel to %d\\n\", cur_channel);\n  wifi_set_channel(cur_channel);\n  wifi_set_promiscuous_rx_cb(detect);\n  os_timer_disarm(&smart_timer);\n  os_timer_setfn(&smart_timer, (os_timer_func_t *)smart_next_channel, NULL);\n  os_timer_arm(&smart_timer, TIME_OUT_PER_CHANNEL, 0);   // no repeat\n\n  if(s){\n    succeed = s;    // init the succeed call back\n    smart_succeed_arg = arg;\n  }\n\n  smart_enable();\n}\n\nvoid station_check_connect(bool smart){\n  mode = wifi_get_opmode();\n  if( (STATION_MODE != mode) && (mode != STATIONAP_MODE) ){\n    return;\n  }\n  uint8_t status = wifi_station_get_connect_status();\n  switch(status){\n    case STATION_GOT_IP:\n      NODE_DBG(\"station_check_connect is called with status: GOT_IP\");\n      if(succeed){\n        succeed(smart_succeed_arg);\n        succeed = NULL; // reset to NULL when succeed\n        smart_succeed_arg = NULL;\n      }\n      return;\n    case STATION_CONNECTING:\n      NODE_DBG(\"station_check_connect is called with status: CONNECTING\");\n      break;\n    case STATION_IDLE:\n      wifi_station_set_auto_connect(true);\n    case STATION_CONNECT_FAIL:\n    case STATION_NO_AP_FOUND:\n      wifi_station_disconnect();\n      wifi_station_connect();\n      NODE_DBG(\"station_check_connect is called with smart: %d\", smart);\n      break;\n    case STATION_WRONG_PASSWORD:\n      if(smart)\n        smart_begin(cur_channel, succeed, smart_succeed_arg);\n      return;\n    default:\n      break;\n  }\n  os_timer_disarm(&smart_timer);\n  os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, smart);\n  os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0);   // no repeat\n}\n"
  },
  {
    "path": "app/smart/smart.h",
    "content": "#ifndef _SMART_H\n#define _SMART_H 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#define MAX_CHANNEL\t14\n\n#define TYPE_SUBTYPE_QOS_DATA \t\t0x88\n#define TYPE_SUBTYPE_MASK\t\t\t0xFC\n\n#define NO_RETRY\t\t0x41\n#define DS_RETRY_MASK\t0x4B\n\n#define BSSID_ADDR\t 4\n#define SOURCE_ADDR\t 10\n#define DEST_ADDR\t16\n#define ADDR_LENGTH\t6\n#define ADDR_MATCH_START (SOURCE_ADDR)\n#define ADDR_MATCH_LENGTH (ADDR_LENGTH*2)\t\n\n#define SEQ_ADDR\t22\n#define SEQ_LEN\t\t2\n#define SEQ_MAX\t\t0x1000\n\n#define BASE_LENGTH\t 82\n\n\n#define SSID_FLAG \t1399\n#define PWD_FLAG\t1459\n#define L_FLAG\t28\n#define C_FLAG\t593\n#define SEP_1\t3\n#define SEP_2\t23\n#define SEP_3\t24\n#define SEP_4\t25\n#define SEP_5\t26\n#define SEP_NUM 2\n\n#define NIBBLE_PER_BYTE\t2\n\n#define SEP_1_INDEX\t2\n\n#if(SEP_1_INDEX==0)\n#define FLAG_NUM  (SEP_NUM+1)\n#elif(SEP_1_INDEX==2)\n#define FLAG_NUM  (SEP_NUM+2)\n#endif\n#define FLAG_MATCH_NUM  (FLAG_NUM-1)\t// only need to match 2 or 3 byte to increase speed.\n\n// #define TI_SMARTCONFIG 1\n\n#define SSID_NIBBLE_MAX (32*NIBBLE_PER_BYTE)\n#define PWD_NIBBLE_MAX (64*NIBBLE_PER_BYTE)\n#define SSID_BIT_MAX (SSID_NIBBLE_MAX/8)\n#define PWD_BIT_MAX (PWD_NIBBLE_MAX/8)\n\t\n#define TIME_OUT_PER_CHANNEL\t(30*1000)\n\n#define STATION_CHECK_TIME\t(2*1000)\n\nstruct _my_addr_map {\n\tuint8 addr[ADDR_LENGTH*3];\n\tuint8_t addr_len;\n\tuint16_t base_len;\n\tint16_t flag[FLAG_NUM];\t\t\n\t// flag[0]: SEP_1, flag[1]: SEP_2, flag[1]: SSID_FLAG.    SEP followed by SSID_FLAG formed flag[]\n\t// if flag[i]==0, means skip this flag match, eg. SSID_FLAG, 0, SEP_1, SEP_2\n\tuint8_t flag_match_num;\n\tint16_t cur_base_seq;\n\tint8_t base_seq_valid;\n\tint8_t ssid_len;\n\tint8_t pwd_len;\n};\n\ntypedef struct _my_addr_map smart_addr_map;\n\ntypedef void (* smart_succeed)(void *arg);\n\nvoid smart_begin(int chnl, smart_succeed s, void *arg);\nvoid station_check_connect(bool smart);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "app/spiffs/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = spiffs.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../libc\nINCLUDES += -I ../platform\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n"
  },
  {
    "path": "app/spiffs/docs/IMPLEMENTING",
    "content": ""
  },
  {
    "path": "app/spiffs/docs/INTEGRATION",
    "content": "* QUICK AND DIRTY INTEGRATION EXAMPLE\n\nSo, assume you're running a Cortex-M3 board with a 2 MB SPI flash on it. The \nSPI flash has 64kB blocks. Your project is built using gnumake, and now you \nwant to try things out.\n\nFirst, you simply copy the files in src/ to your own source folder. Exclude\nall files in test folder. Then you point out these files in your make script \nfor compilation.\n\nAlso copy the spiffs_config.h over from the src/default/ folder.\n\nTry building. This fails, nagging about inclusions and u32_t and whatnot. Open \nthe spiffs_config.h and delete the bad inclusions. Also, add following \ntypedefs:\n\n  typedef signed int s32_t;\n  typedef unsigned int u32_t;\n  typedef signed short s16_t;\n  typedef unsigned short u16_t;\n  typedef signed char s8_t;\n  typedef unsigned char u8_t;\n  \nNow it should build. Over to the mounting business. Assume you already \nimplemented the read, write and erase functions to your SPI flash:\n\n  void my_spi_read(int addr, int size, char *buf)\n  void my_spi_write(int addr, int size, char *buf)\n  void my_spi_erase(int addr, int size)\n\nIn your main.c or similar, include the spiffs.h and do that spiffs struct:\n\n  #include <spiffs.h>\n  \n  static spiffs fs;\n\nAlso, toss up some of the needed buffers:\n\n  #define LOG_PAGE_SIZE       256\n  \n  static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];\n  static u8_t spiffs_fds[32*4];\n  static u8_t spiffs_cache[(LOG_PAGE_SIZE+32)*4];\n  \nNow, write the my_spiffs_mount function:\n\n  void my_spiffs_mount() {\n    spiffs_config cfg;\n    cfg.phys_size = 2*1024*1024; // use all spi flash\n    cfg.phys_addr = 0; // start spiffs at start of spi flash\n    cfg.phys_erase_block = 65536; // according to datasheet\n    cfg.log_block_size = 65536; // let us not complicate things\n    cfg.log_block_size = LOG_PAGE_SIZE; // as we said\n    \n    cfg.hal_read_f = my_spi_read;\n    cfg.hal_write_f = my_spi_write;\n    cfg.hal_erase_f = my_spi_erase;\n    \n    int res = SPIFFS_mount(&fs,\n      &cfg,\n      spiffs_work_buf,\n      spiffs_fds,\n      sizeof(spiffs_fds),\n      spiffs_cache,\n      sizeof(spiffs_cache),\n      0);\n    printf(\"mount res: %i\\n\", res);\n  }\n\nNow, build warns about the my_spi_read, write and erase functions. Wrong \nsignatures, so go wrap them:\n\n  static s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) {\n    my_spi_read(addr, size, dst);\n    return SPIFFS_OK;\n  }\n\n  static s32_t my_spiffs_write(u32_t addr, u32_t size, u8_t *src) {\n    my_spi_write(addr, size, dst);\n    return SPIFFS_OK;\n  }\n\n  static s32_t my_spiffs_erase(u32_t addr, u32_t size) {\n    my_spi_erase(addr, size);\n    return SPIFFS_OK;\n  } \n\nRedirect the config in my_spiffs_mount to the wrappers instead:\n\n    cfg.hal_read_f = my_spiffs_read;\n    cfg.hal_write_f = my_spiffs_write;\n    cfg.hal_erase_f = my_spiffs_erase;\n\nOk, now you should be able to build and run. However, you get this output:\n  \n  mount res: -1\n  \nbut you wanted \n\n  mount res: 0\n  \nThis is probably due to you having experimented with your SPI flash, so it\ncontains rubbish from spiffs's point of view. Do a mass erase and run again.\n\nIf all is ok now, you're good to go. Try creating a file and read it back:\n\n  static void test_spiffs() {\n    char buf[12];\n    \n    // Surely, I've mounted spiffs before entering here\n  \n    spiffs_file fd = SPIFFS_open(&fs, \"my_file\", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);\n    if (SPIFFS_write(&fs, fd, (u8_t *)\"Hello world\", 12) < 0) printf(\"errno %i\\n\", SPIFFS_errno(&fs));\n    SPIFFS_close(&fs, fd); \n  \n    fd = SPIFFS_open(&fs, \"my_file\", SPIFFS_RDWR, 0);\n    if (SPIFFS_read(&fs, fd, (u8_t *)buf, 12) < 0) printf(\"errno %i\\n\", SPIFFS_errno(&fs));\n    SPIFFS_close(&fs, fd);\n  \n    printf(\"--> %s <--\\n\", buf);\n  }\n  \nCompile, run, cross fingers hard, and you'll get the output:\n\n  --> Hello world <-- \n  \nGot errors? Check spiffs.h for error definitions to get a clue what went voodoo.\n\n\n* INTEGRATING SPIFFS\n\nIn order to integrate spiffs to your embedded target, you will basically need:\n - A SPI flash device which your processor can communicate with\n - An implementation for reading, writing and erasing the flash\n - Memory (flash or ram) for the code\n - Memory (ram) for the stack\n\nOther stuff may be needed, threaded systems might need mutexes and so on. \n\n** Logical structure\n\nFirst and foremost, one must decide how to divide up the SPI flash for spiffs. \nHaving the datasheet for the actual SPI flash in hand will help. Spiffs can be \ndefined to use all or only parts of the SPI flash.\n\nIf following seems arcane, read the \"HOW TO CONFIG\" chapter first.\n\n - Decide the logical size of blocks. This must be a multiple of the biggest \n   physical SPI flash block size. To go safe, use the physical block size - \n   which in many cases is 65536 bytes.\n - Decide the logical size of pages. This must be a 2nd logarithm part of the\n   logical block size. To go safe, use 256 bytes to start with.\n - Decide how much of the SPI flash memory to be used for spiffs. This must be\n   on logical block boundary. If unsafe, use 1 megabyte to start with.\n - Decide where on the SPI flash memory the spiffs area should start. This must\n   be on physical block/sector boundary. If unsafe, use address 0.\n\n** SPI flash API\n\nThe target must provide three functions to spiffs:\n\n - s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst)\n - s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src)\n - s32_t (*spiffs_erase)(u32_t addr, u32_t size)\n \nThese functions define the only communication between the SPI flash and the\nspiffs stack. \n \nOn success these must return 0 (or SPIFFS_OK). Anything else will be considered\nan error. \n\nThe size for read and write requests will never exceed the logical page size,\nbut it may be less.\n\nThe address and size on erase requests will always be on physical block size\nboundaries.  \n\n** Mount specification\n\nIn spiffs.h, there is a SPIFFS_mount function defined, used to mount spiffs on\nthe SPI flash.\n\ns32_t SPIFFS_mount(\n\tspiffs *fs, \n\tspiffs_config *config, \n\tu8_t *work,\n    u8_t *fd_space, \n    u32_t fd_space_size,\n    void *cache, \n    u32_t cache_size,\n    spiffs_check_callback check_cb_f)\n    \n - fs            Points to a spiffs struct. This may be totally uninitialized.\n - config        Points to a spiffs_config struct. This struct must be\n                 initialized when mounting. See below.\n - work          A ram memory buffer being double the size of the logical page\n                 size. This buffer is used excessively by the spiffs stack. If\n                 logical page size is 256, this buffer must be 512 bytes.\n - fd_space      A ram memory buffer used for file descriptors.\n - fd_space_size The size of the file descriptor buffer. A file descriptor\n                 normally is around 32 bytes depending on the build config -\n                 the bigger the buffer, the more file descriptors are\n                 available.\n - cache         A ram memory buffer used for cache. Ignored if cache is\n                 disabled in build config. \n - cache_size    The size of the cache buffer. Ignored if cache is disabled in\n                 build config. One cache page will be slightly larger than the \n                 logical page size. The more ram, the more cache pages, the \n                 quicker the system.\n - check_cb_f    Callback function for monitoring spiffs consistency checks and\n                 mending operations. May be null.\n\nThe config struct must be initialized prior to mounting. One must always \ndefine the SPI flash access functions:\n\n spiffs_config.hal_read_f - pointing to the function reading the SPI flash\n\n spiffs_config.hal_write_f - pointing to the function writing the SPI flash\n\n spiffs_config.hal_erase_f - pointing to the function erasing the SPI flash\n \nDepending on the build config - if SPIFFS_SINGLETON is set to zero - following\nparameters must be defined:\n \n spiffs_config.phys_size - the physical number of bytes accounted for \n                           spiffs on the SPI flash\n\n spiffs_config.phys_addr - the physical starting address on the SPI flash\n\n spiffs_config.phys_erase_block - the physical size of the largest block/sector\n                                  on the SPI flash found within the spiffs\n                                  usage address space\n\n spiffs_config.log_block_size - the logical size of a spiffs block\n\n spiffs_config.log_page_size - the logical size of a spiffs page\n \nIf SPIFFS_SINGLETON is set to one, above parameters must be set ny defines in\nthe config header file, spiffs_config.h.\n\n\n** Build config\n\nmakefile: The files needed to be compiled to your target resides in files.mk to\nbe included in your makefile, either by cut and paste or by inclusion.\n\nTypes: spiffs uses the types u8_t, s8_t, u16_t, s16_t, u32_t, s32_t; these must \nbe typedeffed.\n\nspiffs_config.h: you also need to define a spiffs_config.h header. Example of\nthis is found in the default/ directory.\n\n\n** RAM\n\nSpiffs needs ram. It needs a working buffer being double the size of the \nlogical page size. It also needs at least one file descriptor. If cache is \nenabled (highly recommended), it will also need a bunch of cache pages.\n\nSay you have a logical page size of 256 bytes. You want to be able to have four\nfiles open simultaneously, and you can give spiffs four cache pages. This \nroughly sums up to:\n\n256*2 (work buffer) + \n32*4 (file descriptors) + \n(256+32)*4 (cache pages) + 40 (cache metadata)\n\ni.e. 1832 bytes. \n\nThis is apart from call stack usage.\n\nTo get the exact amount of bytes needed on your specific target, enable \nSPIFFS_BUFFER_HELP in spiffs_config.h, rebuild and call:\n\n  SPIFFS_buffer_bytes_for_filedescs\n  SPIFFS_buffer_bytes_for_cache\n  \nHaving these figures you can disable SPIFFS_BUFFER_HELP again to save flash.\n \n\n* HOW TO CONFIG\n\nTODO"
  },
  {
    "path": "app/spiffs/docs/TECH_SPEC",
    "content": "* USING SPIFFS\n\nTODO\n\n\n* SPIFFS DESIGN\n\nSpiffs is inspired by YAFFS. However, YAFFS is designed for NAND flashes, and\nfor bigger targets with much more ram. Nevertheless, many wise thoughts have\nbeen borrowed from YAFFS when writing spiffs. Kudos!\n\nThe main complication writing spiffs was that it cannot be assumed the target\nhas a heap. Spiffs must go along only with the work ram buffer given to it. \nThis forces extra implementation on many areas of spiffs.\n\n\n** SPI flash devices using NOR technology\n\nBelow is a small description of how SPI flashes work internally. This is to\ngive an understanding of the design choices made in spiffs.\n\nSPI flash devices are physically divided in blocks. On some SPI flash devices,\nblocks are further divided into sectors. Datasheets sometimes name blocks as \nsectors and vice versa.\n\nCommon memory capacaties for SPI flashes are 512kB up to 8MB of data, where\nblocks may be 64kB. Sectors can be e.g. 4kB, if supported. Many SPI flashes \nhave uniform block sizes, whereas others have non-uniform - the latter meaning \nthat e.g. the first 16 blocks are 4kB big, and the rest are 64kB.\n\nThe entire memory is linear and can be read and written in random access. \nErasing can only be done block- or sectorwise; or by mass erase.\n\nSPI flashes can normally be erased from 100.000 up to 1.000.000 cycles before\nthey fail.\n\nA clean SPI flash from factory have all bits in entire memory set to one. A\nmass erase will reset the device to this state. Block or sector erasing will\nput the all bits in the area given by the sector or block to ones. Writing to a\nNOR flash pulls ones to zeroes. Writing 0xFF to an address is simply a no-op. \n\nWriting 0b10101010 to a flash address holding 0b00001111 will yield 0b00001010.\n\nThis way of \"write by nand\" is used considerably in spiffs.\n\nCommon characteristics of NOR flashes are quick reads, but slow writes.\n\nAnd finally, unlike NAND flashes, NOR flashes seem to not need any error \ncorrection. They always write correctly I gather.\n\n\n** Spiffs logical structure\n\nSome terminology before proceeding. Physical blocks/sectors means sizes stated\nin the datasheet. Logical blocks and pages is something the integrator choose.\n\n\n** Blocks and pages\n\nSpiffs is allocated to a part or all of the memory of the SPI flash device. \nThis area is divided into logical blocks, which in turn are divided into \nlogical pages. The boundary of a logical block must coincide with one or more \nphysical blocks. The sizes for logical blocks and logical pages always remain\nthe same, they are uniform.\n\nExample: non-uniform flash mapped to spiffs with 128kB logical blocks\n\nPHYSICAL FLASH BLOCKS               SPIFFS LOGICAL BLOCKS: 128kB\n\n+-----------------------+   - - -   +-----------------------+\n| Block 1 : 16kB        |           | Block 1 : 128kB       |\n+-----------------------+           |                       |\n| Block 2 : 16kB        |           |                       |\n+-----------------------+           |                       |\n| Block 3 : 16kB        |           |                       |\n+-----------------------+           |                       |\n| Block 4 : 16kB        |           |                       |\n+-----------------------+           |                       |\n| Block 5 : 64kB        |           |                       |\n+-----------------------+   - - -   +-----------------------+\n| Block 6 : 64kB        |           | Block 2 : 128kB       |\n+-----------------------+           |                       |\n| Block 7 : 64kB        |           |                       |\n+-----------------------+   - - -   +-----------------------+\n| Block 8 : 64kB        |           | Block 3 : 128kB       |\n+-----------------------+           |                       |\n| Block 9 : 64kB        |           |                       |\n+-----------------------+   - - -   +-----------------------+\n| ...                   |           | ...                   |\n\nA logical block is divided further into a number of logical pages. A page \ndefines the smallest data holding element known to spiffs. Hence, if a file\nis created being one byte big, it will occupy one page for index and one page\nfor data - it will occupy 2 x size of a logical page on flash.\nSo it seems it is good to select a small page size.\n\nEach page has a metadata header being normally 5 to 9 bytes. This said, a very\nsmall page size will make metadata occupy a lot of the memory on the flash. A\npage size of 64 bytes will waste 8-14% on metadata, while 256 bytes 2-4%.\nSo it seems it is good to select a big page size.\n\nAlso, spiffs uses a ram buffer being two times the page size. This ram buffer\nis used for loading and manipulating pages, but it is also used for algorithms \nto find free file ids, scanning the file system, etc. Having too small a page\nsize means less work buffer for spiffs, ending up in more reads operations and\neventually gives a slower file system.\n\nChoosing the page size for the system involves many factors:\n - How big is the logical block size\n - What is the normal size of most files\n - How much ram can be spent\n - How much data (vs metadata) must be crammed into the file system\n - How fast must spiffs be\n - Other things impossible to find out\n \nSo, chosing the Optimal Page Size (tm) seems tricky, to say the least. Don't \nfret - there is no optimal page size. This varies from how the target will use\nspiffs. Use the golden rule:\n\n        ~~~   Logical Page Size = Logical Block Size / 256   ~~~\n\nThis is a good starting point. The final page size can then be derived through \nheuristical experimenting for us non-analytical minds.\n\n\n** Objects, indices and look-ups\n\nA file, or an object as called in spiffs, is identified by an object id. \nAnother YAFFS rip-off. This object id is a part of the page header. So, all \npages know to which object/file they belong - not counting the free pages.\n\nAn object is made up of two types of pages: object index pages and data pages.\nData pages contain the data written by user. Index pages contain metadata about\nthe object, more specifically what data pages are part of the object.\n\nThe page header also includes something called a span index. Let's say a file\nis written covering three data pages. The first data page will then have span \nindex 0, the second span index 1, and the last data page will have span index\n2. Simple as that. \n\nFinally, each page header contain flags, telling if the page is used, \ndeleted, finalized, holds index or data, and more.\n\nObject indices also have span indices, where an object index with span index 0\nis referred to as the object index header. This page does not only contain \nreferences to data pages, but also extra info such as object name, object size\nin bytes, flags for file or directory, etc.\n\nIf one were to create a file covering three data pages, named e.g. \n\"spandex-joke.txt\", given object id 12, it could look like this:\n\nPAGE 0  <things to be unveiled soon>\n\nPAGE 1  page header:   [obj_id:12  span_ix:0  flags:USED|DATA]\n        <first data page of joke>\n\nPAGE 2  page header:   [obj_id:12  span_ix:1  flags:USED|DATA]\n        <second data page of joke>\n\nPAGE 3  page header:   [obj_id:545 span_ix:13 flags:USED|DATA]\n        <some data belonging to object 545, probably not very amusing>\n\nPAGE 4  page header:   [obj_id:12  span_ix:2  flags:USED|DATA]\n        <third data page of joke>\n\nPAGE 5  page header:   [obj_id:12  span_ix:0  flags:USED|INDEX]\n        obj ix header: [name:spandex-joke.txt  size:600 bytes  flags:FILE] \n        obj ix:        [1 2 4]\n        \nLooking in detail at page 5, the object index header page, the object index\narray refers to each data page in order, as mentioned before. The index of the\nobject index array correlates with the data page span index.\n\n                            entry ix:  0 1 2\n                              obj ix: [1 2 4]\n                                       | | |\n    PAGE 1, DATA, SPAN_IX 0    --------/ | |\n      PAGE 2, DATA, SPAN_IX 1    --------/ |\n        PAGE 4, DATA, SPAN_IX 2    --------/\n        \nThings to be unveiled in page 0 - well.. Spiffs is designed for systems low on \nram. We cannot keep a dynamic list on the whereabouts of each object index \nheader so we can find a file fast. There might not even be a heap! But, we do \nnot want to scan all page headers on the flash to find the object index header.\n\nThe first page(s) of each block contains the so called object look-up. These \nare not normal pages, they do not have a header. Instead, they are arrays \npointing out what object-id the rest of all pages in the block belongs to.\n\nBy this look-up, only the first page(s) in each block must to scanned to find \nthe actual page which contains the object index header of the desired object.\n\nThe object lookup is redundant metadata. The assumption is that it presents \nless overhead reading a full page of data to memory from each block and search\nthat, instead of reading a small amount of data from each page (i.e. the page \nheader) in all blocks. Each read operation from SPI flash normally contains \nextra data as the read command itself and the flash address. Also, depending on\nthe underlying implementation, other criterions may need to be passed for each \nread transaction, like mutexes and such.\n\nThe veiled example unveiled would look like this, with some extra pages:\n\nPAGE 0  [  12   12  545   12   12   34   34    4    0    0    0    0 ...]\nPAGE 1  page header:   [obj_id:12  span_ix:0  flags:USED|DATA] ...\nPAGE 2  page header:   [obj_id:12  span_ix:1  flags:USED|DATA] ...\nPAGE 3  page header:   [obj_id:545 span_ix:13 flags:USED|DATA] ...\nPAGE 4  page header:   [obj_id:12  span_ix:2  flags:USED|DATA] ...\nPAGE 5  page header:   [obj_id:12  span_ix:0  flags:USED|INDEX] ...\nPAGE 6  page header:   [obj_id:34  span_ix:0  flags:USED|DATA] ...\nPAGE 7  page header:   [obj_id:34  span_ix:1  flags:USED|DATA] ...\nPAGE 8  page header:   [obj_id:4   span_ix:1  flags:USED|INDEX] ...\nPAGE 9  page header:   [obj_id:23  span_ix:0  flags:DELETED|INDEX] ...\nPAGE 10 page header:   [obj_id:23  span_ix:0  flags:DELETED|DATA] ...\nPAGE 11 page header:   [obj_id:23  span_ix:1  flags:DELETED|DATA] ...\nPAGE 12 page header:   [obj_id:23  span_ix:2  flags:DELETED|DATA] ...\n...\n\nOk, so why are page 9 to 12 marked as 0 when they belong to object id 23? These\npages are deleted, so this is marked both in page header flags and in the look\nup. This is an example where spiffs uses NOR flashes \"nand-way\" of writing.\n\nAs a matter of fact, there are two object id's which are special:\n\nobj id 0 (all bits zeroes) - indicates a deleted page in object look up  \nobj id 0xff.. (all bits ones) - indicates a free page in object look up \n\nActually, the object id's have another quirk: if the most significant bit is\nset, this indicates an object index page. If the most significant bit is zero,\nthis indicates a data page. So to be fully correct, page 0 in above example \nwould look like this:\n\nPAGE 0  [  12   12  545   12  *12   34   34   *4    0    0    0    0 ...]\n\nwhere the asterisk means the msb of the object id is set.\n\nThis is another way to speed up the searches when looking for object indices.\nBy looking on the object id's msb in the object lookup, it is also possible \nto find out whether the page is an object index page or a data page.\n\n"
  },
  {
    "path": "app/spiffs/docs/TODO",
    "content": "* When mending lost pages, also see if they fit into length specified in object index header"
  },
  {
    "path": "app/spiffs/params_test.h",
    "content": "/*\n * params_test.h\n *\n *  Created on: May 26, 2013\n *      Author: petera\n */\n\n#ifndef PARAMS_TEST_H_\n#define PARAMS_TEST_H_\n\n// // total emulated spi flash size\n// #define PHYS_FLASH_SIZE       (16*1024*1024)\n// // spiffs file system size\n// #define SPIFFS_FLASH_SIZE     (2*1024*1024)\n// // spiffs file system offset in emulated spi flash\n// #define SPIFFS_PHYS_ADDR      (4*1024*1024)\n\n// #define SECTOR_SIZE         65536\n// #define LOG_BLOCK           (SECTOR_SIZE*2)\n// #define LOG_PAGE            (SECTOR_SIZE/256)\n\n// #define FD_BUF_SIZE     64*6\n// #define CACHE_BUF_SIZE  (LOG_PAGE + 32)*8\n\n// #define ASSERT(c, m) real_assert((c),(m), __FILE__, __LINE__);\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\nvoid real_assert(int c, const char *n, const char *file, int l);\n\n#endif /* PARAMS_TEST_H_ */\n"
  },
  {
    "path": "app/spiffs/spiffs.c",
    "content": "#include \"c_stdio.h\"\n#include \"platform.h\"\n#include \"spiffs.h\"\n  \nspiffs fs;\n\n#define LOG_PAGE_SIZE       256\n  \nstatic u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];\nstatic u8_t spiffs_fds[32*4];\nstatic u8_t spiffs_cache[(LOG_PAGE_SIZE+32)*4];\n\nstatic s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) {\n  platform_flash_read(dst, addr, size);\n  return SPIFFS_OK;\n}\n\nstatic s32_t my_spiffs_write(u32_t addr, u32_t size, u8_t *src) {\n  platform_flash_write(src, addr, size);\n  return SPIFFS_OK;\n}\n\nstatic s32_t my_spiffs_erase(u32_t addr, u32_t size) {\n  u32_t sect_first = platform_flash_get_sector_of_address(addr);\n  u32_t sect_last = sect_first;\n  while( sect_first <= sect_last )\n    if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR )\n      return SPIFFS_ERR_INTERNAL;\n  return SPIFFS_OK;\n} \n\nvoid myspiffs_check_callback(spiffs_check_type type, spiffs_check_report report, u32_t arg1, u32_t arg2){\n  // if(SPIFFS_CHECK_PROGRESS == report) return;\n  // NODE_ERR(\"type: %d, report: %d, arg1: %d, arg2: %d\\n\", type, report, arg1, arg2);\n}\n\n/*******************\nThe W25Q32BV array is organized into 16,384 programmable pages of 256-bytes each. Up to 256 bytes can be programmed at a time. \nPages can be erased in groups of 16 (4KB sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block erase) or \nthe entire chip (chip erase). The W25Q32BV has 1,024 erasable sectors and 64 erasable blocks respectively. \nThe small 4KB sectors allow for greater flexibility in applications that require data and parameter storage. \n\n********************/\n\nvoid spiffs_mount() {\n  spiffs_config cfg;\n  cfg.phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL ); \n  cfg.phys_addr += 0x3000;\n  cfg.phys_addr &= 0xFFFFC000;  // align to 4 sector.\n  cfg.phys_size = INTERNAL_FLASH_SIZE - ( ( u32_t )cfg.phys_addr - INTERNAL_FLASH_START_ADDRESS );\n  cfg.phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet\n  cfg.log_block_size = INTERNAL_FLASH_SECTOR_SIZE; // let us not complicate things\n  cfg.log_page_size = LOG_PAGE_SIZE; // as we said\n  NODE_DBG(\"fs.start:%x,max:%x\",cfg.phys_addr,cfg.phys_size);\n\n  cfg.hal_read_f = my_spiffs_read;\n  cfg.hal_write_f = my_spiffs_write;\n  cfg.hal_erase_f = my_spiffs_erase;\n  \n  int res = SPIFFS_mount(&fs,\n    &cfg,\n    spiffs_work_buf,\n    spiffs_fds,\n    sizeof(spiffs_fds),\n    spiffs_cache,\n    sizeof(spiffs_cache),\n    // myspiffs_check_callback);\n    0);\n  NODE_DBG(\"mount res: %i\", res);\n}\n\n// FS formatting function\n// Returns 1 if OK, 0 for error\nint myspiffs_format( void )\n{\n  SPIFFS_unmount(&fs);\n  u32_t sect_first, sect_last;\n  sect_first = ( u32_t )platform_flash_get_first_free_block_address( NULL ); \n  sect_first += 0x3000;\n  sect_first &= 0xFFFFC000;  // align to 4 sector.\n  sect_first = platform_flash_get_sector_of_address(sect_first);\n  sect_last = INTERNAL_FLASH_SIZE + INTERNAL_FLASH_START_ADDRESS - 4;\n  sect_last = platform_flash_get_sector_of_address(sect_last);\n  NODE_DBG(\"sect_first: %x, sect_last: %x\", sect_first, sect_last);\n  while( sect_first <= sect_last )\n    if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR )\n      return 0;\n  spiffs_mount();\n  return 1;\n}\n\nint myspiffs_check( void )\n{\n  // ets_wdt_disable();\n  // int res = (int)SPIFFS_check(&fs);\n  // ets_wdt_enable();\n  // return res;\n}\n\nint myspiffs_open(const char *name, int flags){\n  return (int)SPIFFS_open(&fs, name, (spiffs_flags)flags, 0);\n}\n\nint myspiffs_close( int fd ){\n  SPIFFS_close(&fs, (spiffs_file)fd);\n  return 0;\n}\nsize_t myspiffs_write( int fd, const void* ptr, size_t len ){\n#if 0\n  if(fd==c_stdout || fd==c_stderr){\n    uart0_tx_buffer((u8_t*)ptr, len);\n    return len;\n  }\n#endif\n  int res = SPIFFS_write(&fs, (spiffs_file)fd, (void *)ptr, len);\n  if (res < 0) {\n    NODE_DBG(\"write errno %i\", SPIFFS_errno(&fs));\n    return 0;\n  }\n  return res;\n}\nsize_t myspiffs_read( int fd, void* ptr, size_t len){\n  int res = SPIFFS_read(&fs, (spiffs_file)fd, ptr, len);\n  if (res < 0) {\n    NODE_DBG(\"read errno %i\", SPIFFS_errno(&fs));\n    return 0;\n  }\n  return res;\n}\nint myspiffs_lseek( int fd, int off, int whence ){\n  return SPIFFS_lseek(&fs, (spiffs_file)fd, off, whence);\n}\nint myspiffs_eof( int fd ){\n  return SPIFFS_eof(&fs, (spiffs_file)fd);\n}\nint myspiffs_tell( int fd ){\n  return SPIFFS_tell(&fs, (spiffs_file)fd);\n}\nint myspiffs_getc( int fd ){\n  unsigned char c = 0xFF;\n  int res;\n  if(!myspiffs_eof(fd)){\n    res = SPIFFS_read(&fs, (spiffs_file)fd, &c, 1);\n    if (res != 1) {\n      NODE_DBG(\"getc errno %i\", SPIFFS_errno(&fs));\n      return (int)EOF;\n    } else {\n      return (int)c;\n    }\n  }\n  return (int)EOF;\n}\nint myspiffs_ungetc( int c, int fd ){\n  return SPIFFS_lseek(&fs, (spiffs_file)fd, -1, SEEK_CUR);\n}\nint myspiffs_flush( int fd ){\n  return SPIFFS_fflush(&fs, (spiffs_file)fd);\n}\nint myspiffs_error( int fd ){\n  return SPIFFS_errno(&fs);\n}\nvoid myspiffs_clearerr( int fd ){\n  fs.errno = SPIFFS_OK;\n}\n#if 0\nvoid test_spiffs() {\n  char buf[12];\n\n  // Surely, I've mounted spiffs before entering here\n  \n  spiffs_file fd = SPIFFS_open(&fs, \"my_file\", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);\n  if (SPIFFS_write(&fs, fd, (u8_t *)\"Hello world\", 12) < 0) NODE_DBG(\"errno %i\", SPIFFS_errno(&fs));\n  SPIFFS_close(&fs, fd); \n\n  fd = SPIFFS_open(&fs, \"my_file\", SPIFFS_RDWR, 0);\n  if (SPIFFS_read(&fs, fd, (u8_t *)buf, 12) < 0) NODE_DBG(\"errno %i\", SPIFFS_errno(&fs));\n  SPIFFS_close(&fs, fd);\n\n  NODE_DBG(\"--> %s <--\", buf);\n}\n#endif\n"
  },
  {
    "path": "app/spiffs/spiffs.h",
    "content": "/*\n * spiffs.h\n *\n *  Created on: May 26, 2013\n *      Author: petera\n */\n\n\n\n#ifndef SPIFFS_H_\n#define SPIFFS_H_\n#include \"c_stdio.h\"\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\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\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\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 */\ntypedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,\n    u32_t arg1, u32_t arg2);\n\n#ifndef SPIFFS_DBG\n#define SPIFFS_DBG(...) \\\n    print(__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/* If the opened file exists, it will be truncated to zero length before opened */\n#define SPIFFS_TRUNC                    (1<<1)\n/* If the opened file does not exist, it will be created before opened */\n#define SPIFFS_CREAT                    (1<<2)\n/* The opened file may only be read */\n#define SPIFFS_RDONLY                   (1<<3)\n/* The opened file may only be writted */\n#define SPIFFS_WRONLY                   (1<<4)\n/* The opened file may be both read and writted */\n#define SPIFFS_RDWR                     (SPIFFS_RDONLY | SPIFFS_WRONLY)\n/* Any writes to the filehandle will never be cached */\n#define SPIFFS_DIRECT                   (1<<5)\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#endif\n} spiffs_config;\n\ntypedef struct {\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 errno;\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} 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  u8_t name[SPIFFS_OBJ_NAME_LEN];\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};\n\ntypedef struct {\n  spiffs *fs;\n  spiffs_block_ix block;\n  int entry;\n} spiffs_DIR;\n\n// functions\n\n/**\n * Initializes the file system dynamic parameters and mounts the filesystem\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_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,\n *                      SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT\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 * 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, u32_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, u32_t len);\n\n/**\n * Moves the read/write file 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 offset\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 */\nvoid SPIFFS_close(spiffs *fs, spiffs_file fh);\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 * 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 * 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);\ns32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);\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\nint myspiffs_open(const char *name, int flags);\nint myspiffs_close( int fd );\nsize_t myspiffs_write( int fd, const void* ptr, size_t len );\nsize_t myspiffs_read( int fd, void* ptr, size_t len);\nint myspiffs_lseek( int fd, int off, int whence );\nint myspiffs_eof( int fd );\nint myspiffs_tell( int fd );\nint myspiffs_getc( int fd );\nint myspiffs_ungetc( int c, int fd );\nint myspiffs_flush( int fd );\nint myspiffs_error( int fd );\nvoid myspiffs_clearerr( int fd );\nint myspiffs_check( void );\n\n#endif /* SPIFFS_H_ */\n"
  },
  {
    "path": "app/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 %i for %04x\\n\", i, pix);\n      cp->last_access = cache->last_access;\n      return cp;\n    }\n  }\n  //SPIFFS_CACHE_DBG(\"CACHE_GET: no cache for %04x\\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 = fs->cfg.hal_write_f(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 %i objid %04x\\n\", ix, cp->obj_id);\n    } else {\n      SPIFFS_CACHE_DBG(\"CACHE_FREE: free cache page %i pix %04x\\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 %i\\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  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#if SPIFFS_CACHE_STATS\n    fs->cache_hits++;\n#endif\n    cp->last_access = cache->last_access;\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 fs->cfg.hal_read_f(\n          addr ,\n          len,\n          dst);\n    }\n#if SPIFFS_CACHE_STATS\n    fs->cache_misses++;\n#endif\n    res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);\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\n    s32_t res2 = fs->cfg.hal_read_f(\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      res = res2;\n    }\n  }\n  u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);\n  c_memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);\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  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 fs->cfg.hal_write_f(addr, len, src);\n    }\n\n    u8_t *mem =  spiffs_get_cache_page(fs, cache, cp->ix);\n    c_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 fs->cfg.hal_write_f(addr, len, src);\n    } else {\n      return SPIFFS_OK;\n    }\n  } else {\n    // no cache page, no write cache - just write thru\n    return fs->cfg.hal_write_f(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  int 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  c_memset(&cache, 0, sizeof(spiffs_cache));\n  cache.cpage_count = cache_entries;\n  cache.cpages = (u8_t *)(fs->cache) + sizeof(spiffs_cache);\n\n  cache.cpage_use_map = 0xffffffff;\n  cache.cpage_use_mask = cache_mask;\n  c_memcpy(fs->cache, &cache, sizeof(spiffs_cache));\n\n  spiffs_cache *c = spiffs_get_cache(fs);\n\n  c_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": "app/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#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\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  // 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  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 %04x 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 %04x to new page %04x\\n\", cur_pix, new_pix);\n          SPIFFS_CHECK_RES(res);\n          *reload_lu = 1;\n          SPIFFS_CHECK_DBG(\"LU: FIXUP: %04x rewritten to %04x, affected objix_pix %04x\\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 %i, 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            if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);\n          } else {\n            if (fs->check_cb_f) fs->check_cb_f(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 %04x to new page %04x\\n\", cur_pix, new_pix);\n          SPIFFS_CHECK_RES(res);\n          *reload_lu = 1;\n          if (fs->check_cb_f) fs->check_cb_f(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 %04x differ in obj_id lu:%04x ph:%04x\\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 %i, 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                if (fs->check_cb_f) fs->check_cb_f(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 %04x as %04x to pix %04x\\n\", cur_pix, new_ph.obj_id, new_pix);\n              if (fs->check_cb_f) fs->check_cb_f(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 %04x as %04x\\n\", cur_pix, new_ph.obj_id);\n              if (fs->check_cb_f) fs->check_cb_f(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: %04x lu/page index marking differ\\n\", cur_pix);\n      spiffs_page_ix data_pix, objix_pix;\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);\n      if (res == SPIFFS_ERR_NOT_FOUND) {\n        res = SPIFFS_OK;\n        objix_pix = 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) {\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 == 0) {\n        SPIFFS_CHECK_DBG(\"LU: FIXUP: other data page exists, make this index\\n\");\n        if (fs->check_cb_f) fs->check_cb_f(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) {\n        SPIFFS_CHECK_DBG(\"LU: FIXUP: other index page exists, make this data\\n\");\n        if (fs->check_cb_f) fs->check_cb_f(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 %04x 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 %04x 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          if (fs->check_cb_f) fs->check_cb_f(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 %04x\\n\", cur_pix);\n    if (fs->check_cb_f) fs->check_cb_f(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    u32_t user_data, void *user_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  if (fs->check_cb_f) fs->check_cb_f(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  s32_t res = SPIFFS_OK;\n\n  if (fs->check_cb_f) fs->check_cb_f(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    if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);\n  }\n\n  if (fs->check_cb_f) fs->check_cb_f(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    c_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      if (fs->check_cb_f) fs->check_cb_f(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\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        // 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 %04x bad pix / LU referenced from page %04x\\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 @ %04x\\n\", data_pix);\n              }\n              // remap index\n              SPIFFS_CHECK_DBG(\"PA: FIXUP: rewriting index pix %04x\\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 %i, cannot mend - delete object\\n\", res);\n                if (fs->check_cb_f) fs->check_cb_f(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                if (fs->check_cb_f) fs->check_cb_f(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 %04x has inconsistent page header ix id/span:%04x/%04x, ref id/span:%04x/%04x flags:%02x\\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 %04x\\n\", p_hdr.obj_id);\n                 if (fs->check_cb_f) fs->check_cb_f(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 %04x, rewrite ix pix %04x id %04x\\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 %i, cannot mend!\\n\", res);\n                   if (fs->check_cb_f) fs->check_cb_f(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                   if (fs->check_cb_f) fs->check_cb_f(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 %04x multiple referenced from page %04x\\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 %04x and page %04x\\n\",\n                      p_hdr.obj_id, cur_pix);\n                  if (fs->check_cb_f) fs->check_cb_f(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      int byte_ix;\n      int 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 %04x 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: %04x, rewrite to this %04x\\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: %04x, delete this %04x\\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: %04x %s%s%s%s, rewrite this %04x\\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 %04x\\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 %04x data spix %04x to point to this pix: %04x\\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 %i, cannot mend!\\n\", res);\n                if (fs->check_cb_f) fs->check_cb_f(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                if (fs->check_cb_f) fs->check_cb_f(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 %04x\\n\", cur_pix);\n              if (fs->check_cb_f) fs->check_cb_f(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 %04x 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 %04x 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 %04x 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 %04x 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    // 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  if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);\n  s32_t res = spiffs_page_consistency_check_i(fs);\n  if (res != SPIFFS_OK) {\n    if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);\n  }\n  if (fs->check_cb_f) fs->check_cb_f(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  int 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\ns32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,\n    int cur_entry, u32_t user_data, void *user_p) {\n  s32_t res_c = SPIFFS_VIS_COUNTINUE;\n  s32_t res = SPIFFS_OK;\n  u32_t *log_ix = (u32_t *)user_p;\n  spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;\n\n  if (fs->check_cb_f) fs->check_cb_f(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 %04x, obj id:%04x spix:%04x header not fully deleted - deleting\\n\",\n          cur_pix, obj_id, p_hdr.span_ix);\n      if (fs->check_cb_f) fs->check_cb_f(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 %04x, obj id:%04x spix:%04x is orphan index - deleting\\n\",\n            cur_pix, obj_id, p_hdr.span_ix);\n        if (fs->check_cb_f) fs->check_cb_f(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  c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n  u32_t obj_id_log_ix = 0;\n  if (fs->check_cb_f) fs->check_cb_f(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    if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);\n  }\n  if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);\n  return res;\n}\n\n"
  },
  {
    "path": "app/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 \"params_test.h\"\n#include \"c_stdio.h\"\n#include \"c_stdlib.h\"\n#include \"c_string.h\"\n#include \"c_stddef.h\"\n#include \"c_types.h\"\n// ----------- >8 ------------\n\ntypedef sint32_t s32_t;\ntypedef uint32_t u32_t;\ntypedef sint16_t s16_t;\ntypedef uint16_t u16_t;\ntypedef sint8_t s8_t;\ntypedef uint8_t u8_t;\n\n// compile time switches\n\n// Set generic spiffs debug output call.\n#ifndef SPIFFS_DGB\n#define SPIFFS_DBG(...)\n#endif\n// Set spiffs debug output call for garbage collecting.\n#ifndef SPIFFS_GC_DGB\n#define SPIFFS_GC_DBG(...)\n#endif\n// Set spiffs debug output call for caching.\n#ifndef SPIFFS_CACHE_DGB\n#define SPIFFS_CACHE_DBG(...)\n#endif\n// Set spiffs debug output call for system consistency checks.\n#ifndef SPIFFS_CHECK_DGB\n#define SPIFFS_CHECK_DBG(...)\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              3\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.\n#ifndef SPIFFS_OBJ_NAME_LEN\n#define SPIFFS_OBJ_NAME_LEN             (32)\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        (64)\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 entering 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 exiting a mutex if you're running on a multithreaded system\n#ifndef SPIFFS_UNLOCK\n#define SPIFFS_UNLOCK(fs)\n#endif\n\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// Set SPFIFS_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         1\n#endif\n#if SPIFFS_TEST_VISUALISATION\n#ifndef spiffs_printf\n#define spiffs_printf(...)                c_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": "app/spiffs/spiffs_gc.c",
    "content": "#include \"spiffs.h\"\n#include \"spiffs_nucleus.h\"\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  u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix);\n  s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);\n\n  SPIFFS_GC_DBG(\"gc: erase block %i\\n\", bix);\n\n  // here we ignore res, just try erasing the block\n  while (size > 0) {\n    SPIFFS_GC_DBG(\"gc: erase %08x:%08x\\n\", addr,  SPIFFS_CFG_PHYS_ERASE_SZ(fs));\n    (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));\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  fs->max_erase_count++;\n  if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) {\n    fs->max_erase_count = 0;\n  }\n\n#if SPIFFS_CACHE\n  {\n    int 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) {\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\", cur_block);\n#if SPIFFS_GC_STATS\n  fs->stats_gc_runs++;\n#endif\n\n  u32_t 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\n    int obj_lookup_page = 0;\n    // check each object lookup page\n    while (res == SPIFFS_OK && obj_lookup_page < 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 && cur_entry < 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          obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);\n          break;\n        }  else {\n          // kill scan, go for next block\n          obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);\n          break;\n        }\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n\n    if (res == SPIFFS_OK && deleted_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs)) {\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  return res;\n}\n\n// Checks if garbaga 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  u32_t free_pages =\n      (SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count\n      - fs->stats_p_allocated - fs->stats_p_deleted;\n  int tries = 0;\n\n  if (fs->free_blocks > 3 &&\n      len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) {\n    return SPIFFS_OK;\n  }\n\n  //printf(\"gcing started  %i dirty, blocks %i free, want %i bytes\\n\", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len);\n\n  do {\n    SPIFFS_GC_DBG(\"\\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\\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, free_pages*SPIFFS_DATA_PAGE_SIZE(fs));\n\n    spiffs_block_ix *cands;\n    int count;\n    spiffs_block_ix cand;\n    res = spiffs_gc_find_candidate(fs, &cands, &count);\n    SPIFFS_CHECK_RES(res);\n    if (count == 0) {\n      SPIFFS_GC_DBG(\"gc_check: no candidates, return\\n\");\n      return res;\n    }\n#if SPIFFS_GC_STATS\n    fs->stats_gc_runs++;\n#endif\n    cand = cands[0];\n    fs->cleaning = 1;\n    //printf(\"gcing: cleaning block %i\\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 %i, result %i\\n\", cand, res);\n    } else {\n      SPIFFS_GC_DBG(\"gc_check: cleaning block %i, result %i\\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\n          - fs->stats_p_allocated - fs->stats_p_deleted;\n\n  } while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||\n      len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));\n  SPIFFS_GC_DBG(\"gc_check: finished\\n\");\n\n  //printf(\"gcing finished %i dirty, blocks %i free, %i pages free, %i tries, res %i\\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  u32_t 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 < 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 < 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:%i pdele:%i\\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  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  c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n\n  // divide up work area into block indices and scores\n  // todo alignment?\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  *block_candidates = cand_blocks;\n\n  u32_t 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 < 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 && cur_entry < 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          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\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 * SPIFFS_GC_HEUR_W_ERASE_AGE;\n      int cand_ix = 0;\n      SPIFFS_GC_DBG(\"gc_check: bix:%i del:%i use:%i score:%i\\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  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  u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n  int cur_entry = 0;\n  spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;\n  spiffs_gc gc;\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 %i\\n\", bix);\n\n  c_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 %i\\n\", fs->free_cursor_block_ix);\n  }\n\n  while (res == SPIFFS_OK && gc.state != FINISHED) {\n    SPIFFS_GC_DBG(\"gc_clean: state = %i entry:%i\\n\", gc.state, cur_entry);\n    gc.obj_id_found = 0;\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 < 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 entry\n      while (scan && res == SPIFFS_OK &&\n          cur_entry - entry_offset < entries_per_page && cur_entry < 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          if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&\n              ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {\n            SPIFFS_GC_DBG(\"gc_clean: FIND_DATA state:%i - found obj id %04x\\n\", gc.state, obj_id);\n            gc.obj_id_found = 1;\n            gc.cur_obj_id = obj_id;\n            scan = 0;\n          }\n          break;\n        case MOVE_OBJ_DATA:\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 %04x:%04x @ %04x\\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 %04x:%04x page %04x to %04x\\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                SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA wipe objix %04x:%04x page %04x\\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 %04x to objix_hdr entry %02x in mem\\n\", new_data_pix, 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 %04x to objix entry %02x in mem\\n\", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));\n              }\n            }\n          }\n          break;\n        case MOVE_OBJ_IX:\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 %04x:%04x page %04x to %04x\\n\", obj_id, p_hdr.span_ix, cur_pix, new_pix);\n              SPIFFS_CHECK_RES(res);\n              spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_UPD, 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              SPIFFS_GC_DBG(\"gc_clean: MOVE_OBJIX wipe objix %04x:%04x page %04x\\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, 0, 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        }\n        cur_entry++;\n      } // per entry\n      obj_lookup_page++;\n    } // per object lookup page\n\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        // 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;\n        cur_entry = 0;\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:%04x\\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        SPIFFS_CHECK_RES(res);\n        SPIFFS_GC_DBG(\"gc_clean: FIND_DATA found object index at page %04x\\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        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        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\n      spiffs_page_ix new_objix_pix;\n      gc.state = FIND_OBJ_DATA;\n      cur_entry = gc.stored_scan_entry_index;\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, &new_objix_pix);\n        SPIFFS_GC_DBG(\"gc_clean: MOVE_DATA store modified objix_hdr page, %04x:%04x\\n\", new_objix_pix, 0);\n        SPIFFS_CHECK_RES(res);\n      } else {\n        // store object index page\n        spiffs_page_ix new_objix_pix;\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, %04x:%04x\\n\", new_objix_pix, objix->p_hdr.span_ix);\n        SPIFFS_CHECK_RES(res);\n        spiffs_cb_object_event(fs, 0, 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      gc.state = FINISHED;\n      break;\n    default:\n      cur_entry = 0;\n      break;\n    }\n    SPIFFS_GC_DBG(\"gc_clean: state-> %i\\n\", gc.state);\n  } // while state != FINISHED\n\n\n  return res;\n}\n\n"
  },
  {
    "path": "app/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\nstatic s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);\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\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  SPIFFS_LOCK(fs);\n  c_memset(fs, 0, sizeof(spiffs));\n  c_memcpy(&fs->cfg, config, sizeof(spiffs_config));\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  c_memset(fd_space, 0, fd_space_size);\n  // align fd_space pointer to pointer size byte boundary, below is safe\n  u8_t ptr_size = sizeof(void*);\n// #pragma GCC diagnostic push\n// #pragma GCC diagnostic ignored \"-Wpointer-to-int-cast\"\n  u8_t addr_lsb = (u8_t)(((u32_t)fd_space) & (ptr_size-1));\n// #pragma GCC diagnostic pop\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, below is safe\n// #pragma GCC diagnostic push\n// #pragma GCC diagnostic ignored \"-Wpointer-to-int-cast\"\n  addr_lsb = (u8_t)(((u32_t)cache) & (ptr_size-1));\n// #pragma GCC diagnostic pop\n  if (addr_lsb) {\n    cache = (u8_t *)cache + (ptr_size-addr_lsb);\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#if SPIFFS_CACHE\n  fs->cache = cache;\n  fs->cache_size = cache_size;\n  spiffs_cache_init(fs);\n#endif\n\n  s32_t res = spiffs_obj_lu_scan(fs);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  SPIFFS_DBG(\"page index byte len:         %i\\n\", SPIFFS_CFG_LOG_PAGE_SZ(fs));\n  SPIFFS_DBG(\"object lookup pages:         %i\\n\", SPIFFS_OBJ_LOOKUP_PAGES(fs));\n  SPIFFS_DBG(\"page pages per block:        %i\\n\", SPIFFS_PAGES_PER_BLOCK(fs));\n  SPIFFS_DBG(\"page header length:          %i\\n\", sizeof(spiffs_page_header));\n  SPIFFS_DBG(\"object header index entries: %i\\n\", SPIFFS_OBJ_HDR_IX_LEN(fs));\n  SPIFFS_DBG(\"object index entries:        %i\\n\", SPIFFS_OBJ_IX_LEN(fs));\n  SPIFFS_DBG(\"available file descriptors:  %i\\n\", fs->fd_count);\n  SPIFFS_DBG(\"free blocks:                 %i\\n\", fs->free_blocks);\n\n  fs->check_cb_f = check_cb_f;\n\n  SPIFFS_UNLOCK(fs);\n\n  return 0;\n}\n\nvoid SPIFFS_unmount(spiffs *fs) {\n  if (!SPIFFS_CHECK_MOUNT(fs)) return;\n  SPIFFS_LOCK(fs);\n  int 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->block_count = 0;\n  SPIFFS_UNLOCK(fs);\n}\n\ns32_t SPIFFS_errno(spiffs *fs) {\n  return fs->errno;\n}\n\ns32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {\n  SPIFFS_API_CHECK_MOUNT(fs);\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);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  res = spiffs_object_create(fs, obj_id, (u8_t*)path, SPIFFS_TYPE_FILE, 0);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  SPIFFS_UNLOCK(fs);\n  return 0;\n}\n\nspiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) {\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  spiffs_page_ix pix;\n\n  s32_t res = spiffs_fd_find_new(fs, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)path, &pix);\n  if ((flags & SPIFFS_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 ((flags & SPIFFS_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {\n    spiffs_obj_id obj_id;\n    res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id);\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, (u8_t*)path, 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_TRUNC;\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, flags);\n  if (res < SPIFFS_OK) {\n    spiffs_fd_return(fs, fd->file_nbr);\n  }\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n  if (flags & SPIFFS_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\n  fd->fdoffset = 0;\n\n  SPIFFS_UNLOCK(fs);\n\n  return fd->file_nbr;\n}\n\ns32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_RDONLY) == 0) {\n    res = SPIFFS_ERR_NOT_READABLE;\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_OK) {\n      fd->fdoffset += avail;\n      SPIFFS_UNLOCK(fs);\n      return avail;\n    } else {\n      SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\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\nstatic s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) {\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(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    buf = (u8_t *)buf + m_len;\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\ns32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {\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  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_WRONLY) == 0) {\n    res = SPIFFS_ERR_NOT_WRITABLE;\n    SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\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_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  SPIFFS_DBG(\"SPIFFS_write %i %04x offs:%i len %i\\n\", fh, fd->obj_id, offset, len);\n\n#if SPIFFS_CACHE_WR\n  if ((fd->flags & SPIFFS_DIRECT) == 0) {\n    if (len < 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 %i for fd %i:&04x, boundary viol, offs:%i size:%i\\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        } 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 %i for fd %i:%04x\\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 %i for fd %i:%04x, offs %i:%i len %i\\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        c_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(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 %i for fd %i:%04x, big write, offs:%i size:%i\\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        res = spiffs_hydro_write(fs, fd, buf, offset, len);\n        SPIFFS_API_CHECK_RES(fs, res);\n      }\n    }\n  }\n#endif\n\n  res = spiffs_hydro_write(fs, fd, buf, offset, len);\n  SPIFFS_API_CHECK_RES(fs, res);\n  fd->fdoffset += len;\n\n  SPIFFS_UNLOCK(fs);\n\n  return res;\n}\n\ns32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  switch (whence) {\n  case SPIFFS_SEEK_CUR:\n    offs = fd->fdoffset+offs;\n    break;\n  case SPIFFS_SEEK_END:\n    offs = (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size) + offs;\n    break;\n  }\n\n  if (offs > fd->size) {\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 0;\n}\n\ns32_t SPIFFS_remove(spiffs *fs, const char *path) {\n  SPIFFS_API_CHECK_MOUNT(fs);\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);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  res = spiffs_object_find_object_index_header_by_name(fs, (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}\n\ns32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES_UNLOCK(fs, res);\n\n  if ((fd->flags & SPIFFS_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}\n\nstatic s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {\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;\n  s->type = objix_hdr.type;\n  s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;\n  strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN);\n\n  return res;\n}\n\ns32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) {\n  SPIFFS_API_CHECK_MOUNT(fs);\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, (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_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n\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.\nstatic s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {\n  s32_t res = SPIFFS_OK;\n#if 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_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 %i for fd %i:%04x, flush, offs:%i size:%i\\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->errno = res;\n      }\n      spiffs_cache_fd_release(fs, fd->cache_page);\n    }\n  }\n#endif\n\n  return res;\n}\n\ns32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {\n  SPIFFS_API_CHECK_MOUNT(fs);\n  s32_t res = SPIFFS_OK;\n#if SPIFFS_CACHE_WR\n  SPIFFS_LOCK(fs);\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\nvoid SPIFFS_close(spiffs *fs, spiffs_file fh) {\n  if (!SPIFFS_CHECK_MOUNT(fs)) {\n    fs->errno = SPIFFS_ERR_NOT_MOUNTED;\n    return;\n  }\n  SPIFFS_LOCK(fs);\n\n#if SPIFFS_CACHE\n  spiffs_fflush_cache(fs, fh);\n#endif\n  spiffs_fd_return(fs, fh);\n\n  SPIFFS_UNLOCK(fs);\n}\n\nspiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {\n  if (!SPIFFS_CHECK_MOUNT(fs)) {\n    fs->errno = SPIFFS_ERR_NOT_MOUNTED;\n    return 0;\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    u32_t user_data,\n    void *user_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_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    return SPIFFS_OK;\n  }\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->errno = SPIFFS_ERR_NOT_MOUNTED;\n    return 0;\n  }\n  SPIFFS_LOCK(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    ret = e;\n  } else {\n    d->fs->errno = res;\n  }\n  SPIFFS_UNLOCK(fs);\n  return ret;\n}\n\ns32_t SPIFFS_closedir(spiffs_DIR *d) {\n  SPIFFS_API_CHECK_MOUNT(d->fs);\n  return 0;\n}\n\ns32_t SPIFFS_check(spiffs *fs) {\n  s32_t res;\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// NODE_ERR(\"before spiffs_object_index_consistency_check\\n\");\n  res = spiffs_page_consistency_check(fs);\n// NODE_ERR(\"spiffs_page_consistency_check\\n\");\n  res = spiffs_obj_lu_scan(fs);\n// NODE_ERR(\"spiffs_obj_lu_scan\\n\");\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  res = (fd->fdoffset == fd->size);\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\ns32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  spiffs_fd *fd;\n  s32_t res;\n  res = spiffs_fd_get(fs, fh, &fd);\n  SPIFFS_API_CHECK_RES(fs, res);\n\n#if SPIFFS_CACHE_WR\n  spiffs_fflush_cache(fs, fh);\n#endif\n\n  res = fd->fdoffset;\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n\n#if SPIFFS_TEST_VISUALISATION\ns32_t SPIFFS_vis(spiffs *fs) {\n  s32_t res = SPIFFS_OK;\n  SPIFFS_API_CHECK_MOUNT(fs);\n  SPIFFS_LOCK(fs);\n\n  u32_t 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 < 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 < 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(\"%4i \", 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: %i\\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: %i\\n\", fs->max_erase_count);\n  spiffs_printf(\"last_errno:  %i\\n\", fs->errno);\n  spiffs_printf(\"blocks:      %i\\n\", fs->block_count);\n  spiffs_printf(\"free_blocks: %i\\n\", fs->free_blocks);\n  spiffs_printf(\"page_alloc:  %i\\n\", fs->stats_p_allocated);\n  spiffs_printf(\"page_delet:  %i\\n\", fs->stats_p_deleted);\n\n  SPIFFS_UNLOCK(fs);\n  return res;\n}\n#endif\n"
  },
  {
    "path": "app/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\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\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 fs->cfg.hal_read_f(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 fs->cfg.hal_write_f(addr, len, src);\n}\n\n#endif\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  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\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_data             any data, passed to the callback visitor function\n// @param user_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    u32_t user_data,\n    void *user_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  u32_t entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));\n\n  // wrap initial\n  if (cur_entry >= 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      // block wrap\n      cur_block = 0;\n      cur_block_addr = 0;\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 < 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 < 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_data,\n                user_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\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    u32_t user_data,\n    void *user_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// Scans thru all obj lu and counts free, deleted and used pages\n// Find the maximum block erase count\ns32_t spiffs_obj_lu_scan(\n    spiffs *fs) {\n  s32_t res;\n  spiffs_block_ix bix;\n  int entry;\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  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    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  return res;\n}\n\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);\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;\n    if (*lu_entry == 0) {\n      fs->free_blocks--;\n    }\n  }\n  if (res == SPIFFS_VIS_END) {\n    SPIFFS_DBG(\"fs full\\n\");\n  }\n\n  return res == SPIFFS_VIS_END ? SPIFFS_ERR_FULL : res;\n}\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    u32_t user_data,\n    void *user_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_data &&\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_p == 0 || *((spiffs_page_ix *)user_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      (u32_t)spix,\n      exclusion_pix ? &exclusion_pix : 0,\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      (u32_t)spix,\n      exclusion_pix ? &exclusion_pix : 0,\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// 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\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\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\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    u8_t name[SPIFFS_OBJ_NAME_LEN],\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, 0);\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 @ %04x bix:%i entry:%i\\n\", 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, (char *)name, SPIFFS_OBJ_NAME_LEN);\n\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, 0, 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\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    u8_t name[SPIFFS_OBJ_NAME_LEN],\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, (char *)name, SPIFFS_OBJ_NAME_LEN);\n  }\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, fd, SPIFFS_EV_IX_UPD, 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\nvoid spiffs_cb_object_event(\n    spiffs *fs,\n    spiffs_fd *fd,\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  // update index caches in all file descriptors\n  obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n  int 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->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;\n    if (spix == 0) {\n      if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {\n        SPIFFS_DBG(\"       callback: setting fd %i:%04x objix_hdr_pix to %04x, size:%i\\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 if (ev == SPIFFS_EV_IX_DEL) {\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_NEW || ev == SPIFFS_EV_IX_UPD) {\n        SPIFFS_DBG(\"       callback: setting fd %i:%04x span:%04x objix_pix to %04x\\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\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  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 %i is obj id %04x\\n\", fd->file_nbr, fd->obj_id);\n\n  return res;\n}\n\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  res = spiffs_gc_check(fs, len);\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: %04x store objix %04x:%04x, written %i\\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, offset+written, &new_objix_hdr_page);\n            SPIFFS_CHECK_RES(res);\n            SPIFFS_DBG(\"append: %04x store new objix_hdr, %04x:%04x, written %i\\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, fd, 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, offset+written, &new_objix_hdr_page);\n          SPIFFS_CHECK_RES(res);\n          SPIFFS_DBG(\"append: %04x store new size I %i in objix_hdr, %04x:%04x, written %i\\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: %04x load objixhdr page %04x:%04x\\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          spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);\n          // quick \"load\" of new object index page\n          c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));\n          c_memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));\n          SPIFFS_DBG(\"append: %04x create objix page, %04x:%04x, written %i\\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: %04x find objix span_ix:%04x\\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: %04x found object index at page %04x\\n\", fd->obj_id, 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        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: %04x store new data page, %04x:%04x offset:%i, len %i, written %i\\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: %04x store to existing data page, %04x:%04x offset:%i, len %i, written %i\\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: %04x wrote page %04x to objix_hdr entry %02x 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: %04x wrote page %04x to objix entry %02x in mem\\n\", fd->obj_id\n          , data_page, 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: %04x store objix page, %04x:%04x, written %i\\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, fd, 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, offset+written, &new_objix_hdr_page);\n    SPIFFS_DBG(\"append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i\\n\", fd->obj_id\n        , offset+written, new_objix_hdr_page, 0, written);\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: %04x store fresh objix_hdr page, %04x:%04x, written %i\\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, fd, SPIFFS_EV_IX_UPD, 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, offset+written, &new_objix_hdr_page);\n      SPIFFS_DBG(\"append: %04x store modified objix_hdr page, %04x:%04x, written %i\\n\", fd->obj_id\n          , new_objix_hdr_page, 0, written);\n      SPIFFS_CHECK_RES(res2);\n    }\n  }\n\n  return res;\n}\n\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);\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, &new_objix_hdr_pix);\n          SPIFFS_DBG(\"modify: store modified objix_hdr page, %04x:%04x, written %i\\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, %04x:%04x, written %i\\n\", new_objix_pix, objix->p_hdr.span_ix, written);\n          SPIFFS_CHECK_RES(res);\n          spiffs_cb_object_event(fs, fd, 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 %04x:%04x\\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:%04x\\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 %04x\\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, %04x:%04x offset:%i, len %i, written %i\\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:%04x, dst:%04x:%04x offset:%i, len %i, written %i\\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 %04x to objix_hdr entry %02x 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 %04x to objix entry %02x in mem\\n\", data_pix, 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, %04x:%04x, written %i\\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, fd, 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, &new_objix_hdr_pix);\n    SPIFFS_DBG(\"modify: store modified objix_hdr page, %04x:%04x, written %i\\n\", new_objix_hdr_pix, 0, written);\n    SPIFFS_CHECK_RES(res2);\n  }\n\n  return res;\n}\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    u32_t user_data,\n    void *user_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((char *)user_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    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      0,\n      name,\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// 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) {\n  s32_t res = SPIFFS_OK;\n  spiffs *fs = fd->fs;\n\n  res = spiffs_gc_check(fs, 0);\n  SPIFFS_CHECK_RES(res);\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 == 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 && 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 %04x:%04x\\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, fd, 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\n          SPIFFS_DBG(\"truncate: update objix hdr page %04x:%04x to size %i\\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, cur_size, &new_objix_hdr_pix);\n          SPIFFS_CHECK_RES(res);\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 %04x:%04x for data spix:%04x\\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    if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) {\n      // delete full data page\n      res = spiffs_page_data_check(fs, fd, data_pix, data_spix);\n      if (res != SPIFFS_OK) break;\n\n      res = spiffs_page_delete(fs, data_pix);\n      if (res != SPIFFS_OK) break;\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 %04x for data spix:%04x, cur_size:%i\\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 %i bytes from data page %04x for data spix:%04x, cur_size:%i\\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 %04x to objix_hdr entry %02x in mem\\n\", new_data_pix, 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 %04x to objix entry %02x in mem\\n\", new_data_pix, 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) {\n        // remove object altogether\n        SPIFFS_DBG(\"truncate: remove object index header page %04x\\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, fd, 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 %04x\\n\", objix_pix);\n        c_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, 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, 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, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);\n    SPIFFS_DBG(\"truncate: store modified objix page, %04x:%04x\\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, cur_size, &new_objix_hdr_pix);\n    SPIFFS_CHECK_RES(res);\n  }\n  fd->size = cur_size;\n\n  return res;\n}\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    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 %04x:%04x\\n\", fd->obj_id, cur_objix_spix);\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      SPIFFS_DBG(\"read: load objix page %04x:%04x for data spix:%04x\\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\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:%i rd:%i data spix:%04x is data_pix:%04x addr:%08x\\n\", cur_offset, len_to_read, data_spix, data_pix,\n        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\ntypedef struct {\n  spiffs_obj_id min_obj_id;\n  spiffs_obj_id max_obj_id;\n  u32_t compaction;\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    u32_t user_data, void *user_p) {\n  if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) {\n    spiffs_obj_id min_obj_id = user_data;\n    id &= ~SPIFFS_OBJ_ID_IX_FLAG;\n    int bit_ix = (id-min_obj_id) & 7;\n    int byte_ix = (id-min_obj_id) >> 3;\n    if (byte_ix >= 0 && 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    u32_t user_data, void *user_p) {\n  if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED && (id & SPIFFS_OBJ_ID_IX_FLAG)) {\n    s32_t res;\n    spiffs_free_obj_id_state *state = (spiffs_free_obj_id_state *)user_p;\n    spiffs_page_header ph;\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_header), (u8_t*)&ph);\n    if (res == SPIFFS_OK && ph.span_ix == 0 &&\n        ((ph.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      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 %i for id %04x min:%04x max%04x comp:%i\\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 bitmasked is searched for a free id\ns32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id) {\n  s32_t res = SPIFFS_OK;\n  u32_t max_objects = (SPIFFS_CFG_PHYS_SZ(fs) / (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(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  while (res == SPIFFS_OK && free_obj_id == SPIFFS_OBJ_ID_FREE) {\n    if (state.max_obj_id - state.min_obj_id <= SPIFFS_CFG_LOG_PAGE_SZ(fs)*8) {\n      // possible to represent in bitmap\n      int i, j;\n      SPIFFS_DBG(\"free_obj_id: BITM min:%04x max:%04x\\n\", state.min_obj_id, state.max_obj_id);\n\n      c_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, state.min_obj_id, 0, 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        int 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:%i min_count:%i min:%04x max:%04x compact:%i\\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:%04x min:%04x -> %04x\\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_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:%04x max:%04x compact:%i\\n\", state.min_obj_id, state.max_obj_id, state.compaction);\n\n      c_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, 0, &state, 0, 0);\n      if (res == SPIFFS_VIS_END) res = SPIFFS_OK;\n      SPIFFS_CHECK_RES(res);\n    }\n  }\n\n  return res;\n}\n\ns32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd) {\n  int 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}\n\ns32_t spiffs_fd_return(spiffs *fs, spiffs_file f) {\n  if (f <= 0 || f > 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  return SPIFFS_OK;\n}\n\ns32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) {\n  if (f <= 0 || f > 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"
  },
  {
    "path": "app/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#define SPIFFS_VIS_COUNTINUE            (SPIFFS_ERR_INTERNAL - 20)\n#define SPIFFS_VIS_COUNTINUE_RELOAD     (SPIFFS_ERR_INTERNAL - 21)\n#define SPIFFS_VIS_END                  (SPIFFS_ERR_INTERNAL - 22)\n\n#define SPIFFS_EV_IX_UPD                0\n#define SPIFFS_EV_IX_NEW                1\n#define SPIFFS_EV_IX_DEL                2\n\n#define SPIFFS_OBJ_ID_IX_FLAG           (1<<(8*sizeof(spiffs_obj_id)-1))\n\n#define SPIFFS_UNDEFINED_LEN            (-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_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#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\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\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)->block_count > 0)\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)->errno = SPIFFS_ERR_NOT_MOUNTED; \\\n    return -1; \\\n  }\n\n#define SPIFFS_API_CHECK_RES(fs, res) \\\n  if ((res) < SPIFFS_OK) { \\\n    (fs)->errno = (res); \\\n    return -1; \\\n  }\n\n#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \\\n  if ((res) < SPIFFS_OK) { \\\n    (fs)->errno = (res); \\\n    SPIFFS_UNLOCK(fs); \\\n    return -1; \\\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\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_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} spiffs_fd;\n\n\n// object structs\n\n// page header, part of each page except object lookup pages\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  // 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  // alignment2\n  u8_t _align2[4 - (sizeof(spiffs_obj_type)&3)==0 ? 4 : (sizeof(spiffs_obj_type)&3)];\n  // name of object\n  u8_t name[SPIFFS_OBJ_NAME_LEN];\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    u32_t user_data, void *user_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    u32_t user_data,\n    void *user_p,\n    spiffs_block_ix *block_ix,\n    int *lu_entry);\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\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    u8_t name[SPIFFS_OBJ_NAME_LEN],\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    u8_t name[SPIFFS_OBJ_NAME_LEN],\n    u32_t size,\n    spiffs_page_ix *new_pix);\n\nvoid spiffs_cb_object_event(\n    spiffs *fs,\n    spiffs_fd *fd,\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    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\ns32_t spiffs_gc_clean(\n    spiffs *fs,\n    spiffs_block_ix bix);\n\ns32_t spiffs_gc_quick(\n    spiffs *fs);\n\n// ---------------\n\ns32_t spiffs_fd_find_new(\n    spiffs *fs,\n    spiffs_fd **fd);\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_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": "app/ssl/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nUP_EXTRACT_DIR = ..\nGEN_LIBS = libssl.a\nCOMPONENTS_libssl = crypto/libsslcrypto.a\t\\\n\t\t\t\t\t\tssl/libsslssl.a\t\\\n\t\t\t\t\tapp/libsslapp.a\t\nendif\n\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/ssl/app/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\n\nGEN_LIBS = libsslapp.a\n\nendif\n\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/ssl/app/espconn_secure.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: espconn_encry.c\n *\n * Description: data encrypt interface\n *\n * Modification history:\n *     2014/3/31, v1.0 create this file.\n*******************************************************************************/\n\n#include \"lwip/netif.h\"\n#include \"lwip/inet.h\"\n#include \"netif/etharp.h\"\n#include \"lwip/tcp.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/init.h\"\n#include \"ets_sys.h\"\n#include \"os_type.h\"\n//#include \"os.h\"\n\n#include \"ssl/app/espconn_ssl.h\"\n\n/******************************************************************************\n * FunctionName : espconn_encry_connect\n * Description  : The function given as the connect\n * Parameters   : espconn -- the espconn used to listen the connection\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_secure_connect(struct espconn *espconn)\n{\t\n\tif (espconn == NULL)\n\t\treturn ESPCONN_ARG;\n\t\n\treturn espconn_ssl_client(espconn);\n}\n\n/******************************************************************************\n * FunctionName : espconn_encry_disconnect\n * Description  : The function given as the disconnect\n * Parameters   : espconn -- the espconn used to listen the connection\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_secure_disconnect(struct espconn *espconn)\n{\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n\tif (espconn == NULL)\n\t\treturn ESPCONN_ARG;\n\n\tvalue = espconn_find_connection(espconn, &pnode);\n\tif (value){\n\t\tespconn_ssl_disconnect(pnode);\n\t\treturn ESPCONN_OK;\n\t}\n\telse\n\t\treturn ESPCONN_ARG;\n}\n\n/******************************************************************************\n * FunctionName : espconn_encry_sent\n * Description  : sent data for client or server\n * Parameters   : espconn -- espconn to set for client or server\n * \t\t\t\t  psent -- data to send\n *                length -- length of data to send\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length)\n{\n\tespconn_msg *pnode = NULL;\n\tbool value = false;\n\tif (espconn == NULL)\n\t\treturn ESPCONN_ARG;\n\n\tespconn ->state = ESPCONN_WRITE;\n\tvalue = espconn_find_connection(espconn, &pnode);\n\tif (value){\n\t\tespconn_ssl_sent(pnode, psent, length);\n\t\treturn ESPCONN_OK;\n\t}\n\telse\n\t\treturn ESPCONN_ARG;\n}\n\nsint8 ICACHE_FLASH_ATTR\nespconn_secure_accept(struct espconn *espconn)\n{\n\tif (espconn == NULL)\n\t\treturn ESPCONN_ARG;\n\n\treturn espconn_ssl_server(espconn);\n}\n\n\n"
  },
  {
    "path": "app/ssl/app/espconn_ssl.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: espconn_ssl.c\n *\n * Description: ssl encrypt interface\n *\n * Modification history:\n *     2014/3/31, v1.0 create this file.\n*******************************************************************************/\n\n#include \"lwip/netif.h\"\n#include \"netif/etharp.h\"\n#include \"lwip/tcp.h\"\n#include \"lwip/ip.h\"\n#include \"lwip/init.h\"\n#include \"lwip/tcp_impl.h\"\n\n#include \"ssl/ssl_os_port.h\"\n\n#include \"ssl/app/espconn_ssl.h\"\n#include \"ets_sys.h\"\n#include \"os_type.h\"\n//#include \"os.h\"\n#include \"lwip/app/espconn.h\"\n\nstruct pbuf *psslpbuf = NULL;\nextern espconn_msg *plink_active;\n\nstatic err_t espconn_ssl_crecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);\nstatic err_t espconn_ssl_srecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);\n\nstatic void espconn_ssl_sclose(void *arg, struct tcp_pcb *pcb);\nstatic void espconn_ssl_cclose(void *arg, struct tcp_pcb *pcb);\n\n/////////////////////////////common function///////////////////////////////////\n/******************************************************************************\n * FunctionName : display_session_id\n * Description  : Display what session id we have.\n * Parameters   :\n * Returns      :\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR display_session_id(SSL *ssl)\n{\n    int i;\n    const uint8_t *session_id = ssl_get_session_id(ssl);\n    int sess_id_size = ssl_get_session_id_size(ssl);\n\n    if (sess_id_size > 0) {\n        ssl_printf(\"-----BEGIN SSL SESSION PARAMETERS-----\\n\");\n\n        for (i = 0; i < sess_id_size; i++) {\n            ssl_printf(\"%02x\", session_id[i]);\n        }\n\n        ssl_printf(\"\\n-----END SSL SESSION PARAMETERS-----\\n\");\n        //TTY_FLUSH();\n    }\n}\n\n/******************************************************************************\n * FunctionName : display_cipher\n * Description  : Display what cipher we are using\n * Parameters   :\n * Returns      :\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR display_cipher(SSL *ssl)\n{\n    ssl_printf(\"CIPHER is \");\n\n    switch (ssl_get_cipher_id(ssl)) {\n        case SSL_AES128_SHA:\n            ssl_printf(\"AES128-SHA\");\n            break;\n\n        case SSL_AES256_SHA:\n            ssl_printf(\"AES256-SHA\");\n            break;\n\n        case SSL_RC4_128_SHA:\n            ssl_printf(\"RC4-SHA\");\n            break;\n\n        case SSL_RC4_128_MD5:\n            ssl_printf(\"RC4-MD5\");\n            break;\n\n        default:\n            ssl_printf(\"Unknown - %d\", ssl_get_cipher_id(ssl));\n            break;\n    }\n\n    ssl_printf(\"\\n\");\n    //TTY_FLUSH();\n}\n\n/******************************************************************************\n * FunctionName : espconn_ssl_reconnect\n * Description  : reconnect with host\n * Parameters   : arg -- Additional argument to pass to the callback function\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_ssl_reconnect(void *arg)\n{\n\tespconn_msg *pssl_recon = arg;\n    struct espconn *espconn = NULL;\n    ssl_msg *pssl = NULL;\n    sint8 ssl_reerr = 0;\n    if (pssl_recon != NULL) {\n    \tespconn = pssl_recon->preverse;\n    \tif (pssl_recon->pespconn != NULL){\n    \t\tif (espconn != NULL){\n    \t\t\t/*espconn_copy_partial(espconn, pssl_recon->pespconn);\n    \t\t\tif (pssl_recon->pespconn->proto.tcp != NULL){\n    \t\t\t\tos_free(pssl_recon->pespconn->proto.tcp);\n    \t\t\t\tpssl_recon->pespconn->proto.tcp = NULL;\n    \t\t\t}\n    \t\t\tos_free(pssl_recon->pespconn);\n    \t\t\tpssl_recon->pespconn = NULL;*/\n    \t\t\tespconn = pssl_recon->preverse;\n    \t\t} else {\n    \t\t\tespconn = pssl_recon->pespconn;\n    \t\t}\n    \t}\n        pssl = pssl_recon->pssl;\n        ssl_reerr = pssl_recon->pcommon.err;\n        if (pssl != NULL) {\n            if (pssl->ssl) {\n                ssl_free(pssl->ssl);\n            }\n\n            if (pssl->ssl_ctx) {\n                ssl_ctx_free(pssl->ssl_ctx);\n            }\n\n            os_free(pssl);\n            pssl = NULL;\n            pssl_recon->pssl = pssl;\n        }\n        os_free(pssl_recon);\n        pssl_recon = NULL;\n        if (espconn ->proto.tcp->reconnect_callback != NULL) {\n            espconn ->proto.tcp->reconnect_callback(espconn, ssl_reerr);\n        }\n    } else {\n        ssl_printf(\"espconn_ssl_reconnect err\\n\");\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_ssl_dissuccessful\n * Description  : as\n * Parameters   :\n * Returns      :\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_ssl_dissuccessful(void *arg)\n{\n\tespconn_msg *pdiscon = arg;\n    struct espconn *espconn = NULL;\n    struct tcp_pcb *pcb = NULL;\n    ssl_msg *pssl = NULL;\n    if (pdiscon != NULL) {\n    \tespconn = pdiscon->preverse;\n    \tif (pdiscon->pespconn != NULL){\n    \t\tif (espconn != NULL){\n    \t\t\t/*espconn_copy_partial(espconn, pdiscon->pespconn);\n    \t\t\tif (pdiscon->pespconn->proto.tcp != NULL){\n    \t\t\t\tos_free(pdiscon->pespconn->proto.tcp);\n    \t\t\t\tpdiscon->pespconn->proto.tcp = NULL;\n    \t\t\t}\n    \t\t\tos_free(pdiscon->pespconn);\n    \t\t\tpdiscon->pespconn = NULL;*/\n    \t\t\tespconn = pdiscon->preverse;\n    \t\t} else{\n    \t\t\tespconn = pdiscon->pespconn;\n    \t\t}\n    \t\tpcb = pdiscon->pcommon.pcb;\n    \t\ttcp_arg(pcb, NULL);\n    \t\ttcp_err(pcb, NULL);\n    \t}\n\n        pssl = pdiscon->pssl;\n\n        if (pssl != NULL) {\n            if (pssl->ssl) {\n                ssl_free(pssl->ssl);\n            }\n\n            if (pssl->ssl_ctx) {\n                ssl_ctx_free(pssl->ssl_ctx);\n            }\n\n            os_free(pssl);\n            pssl = NULL;\n            pdiscon->pssl = pssl;\n        }\n\n        os_free(pdiscon);\n        pdiscon = NULL;\n        if (espconn ->proto.tcp->disconnect_callback != NULL) {\n            espconn ->proto.tcp->disconnect_callback(espconn);\n        }\n    } else {\n        espconn_printf(\"espconn_ssl_dissuccessful err\\n\");\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_ssl_write\n * Description  : sent data for client or server\n * Parameters   : void *arg -- client or server to send\n *                uint8* psent -- Data to send\n *                uint16 length -- Length of data to send\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_ssl_sent(void *arg, uint8 *psent, uint16 length)\n{\n\tespconn_msg *pssl_sent = arg;\n    struct tcp_pcb *pcb = NULL;\n    ssl_msg *pssl = NULL;\n    u16_t len = 0;\n    int res = 0;\n\n    ssl_printf(\"espconn_ssl_sent pcb %p psent %p length %d\\n\", arg, psent, length);\n\n    if (pssl_sent == NULL || psent == NULL || length == 0) {\n        return;\n    }\n\n    pcb = pssl_sent->pcommon.pcb;\n\tpssl = pssl_sent->pssl;\n    if (RT_MAX_PLAIN_LENGTH < length) {\n        len = RT_MAX_PLAIN_LENGTH;\n    } else {\n        len = length;\n    }\n\n    if (pssl != NULL) {\n        if (pssl->ssl != NULL) {\n            pssl->ssl->SslClient_pcb = pcb;\n            res = ssl_write(pssl->ssl, psent, len);\n            pssl_sent->pcommon.ptrbuf = psent + len;\n            pssl_sent->pcommon.cntr = length - len;\n        }\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_sent_packet\n * Description  : sent data for client or server\n * Parameters   : void *arg -- client or server to send\n *                uint8* psent -- Data to send\n *                uint16 length -- Length of data to send\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR\nespconn_sent_packet(struct tcp_pcb *pcb, uint8 *psent, uint16 length)\n{\n\terr_t err = 0;\n\tu16_t len = 0;\n\tif (pcb == NULL || psent == NULL || length == 0) {\n\t   return;\n\t}\n\n\tif (tcp_sndbuf(pcb) < length) {\n\t   len = tcp_sndbuf(pcb);\n\t} else {\n\t   len = length;\n\t}\n\n\tif (len > (2 * pcb->mss)) {\n\t   len = 2 * pcb->mss;\n\t}\n\n\tdo {\n\t   err = tcp_write(pcb, psent, len, 0);\n\t   if (err == ERR_MEM) {\n\t      len /= 2;\n\t   }\n\t} while (err == ERR_MEM && len > 1);\n\n\tif (err == ERR_OK) {\n\t   err = tcp_output(pcb);\n\t}\n}\n\n////////////////////////////////client function////////////////////////////////\n/******************************************************************************\n * FunctionName : espconn_ssl_cclose_cb\n * Description  : as\n * Parameters   :\n * Returns      :\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_ssl_cclose_cb(void *arg)\n{\n    static uint16 timecount = 0;\n    espconn_msg *pcclose_cb = arg;\n\n    if (pcclose_cb == NULL) {\n        return;\n    }\n\n    struct tcp_pcb *pcb = pcclose_cb->pcommon.pcb;\n\n    ssl_printf(\"espconn_ssl_cclose_cb %d %d\\n\", pcb->state, pcb->nrtx);\n\n    if (pcb->state == TIME_WAIT || pcb->state == CLOSED) {\n    \tpcclose_cb->pespconn ->state = ESPCONN_CLOSE;\n    \t/*remove the node from the client's active connection list*/\n    \tespconn_list_delete(&plink_active, pcclose_cb);\n        espconn_ssl_dissuccessful((void *)pcclose_cb);\n    } else {\n    \tos_timer_arm(&pcclose_cb->pcommon.ptimer, TCP_FAST_INTERVAL, 0);\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_sslclient_close\n * Description  : The connection shall be actively closed.\n * Parameters   : pcb -- Additional argument to pass to the callback function\n *                pcb -- the pcb to close\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_ssl_cclose(void *arg, struct tcp_pcb *pcb)\n{\n    espconn_msg *pcclose = arg;\n\n    os_timer_disarm(&pcclose->pcommon.ptimer);\n    os_timer_setfn(&pcclose->pcommon.ptimer, espconn_ssl_cclose_cb, pcclose);\n    os_timer_arm(&pcclose->pcommon.ptimer, TCP_FAST_INTERVAL, 0);\n    tcp_recv(pcb, NULL);\n    pcclose->pcommon.err = tcp_close(pcb);\n    ssl_printf(\"espconn_ssl_cclose %d\\n\", pcclose->pcommon.err);\n\n    if (pcclose->pcommon.err != ERR_OK) {\n        /* closing failed, try again later */\n        tcp_recv(pcb, espconn_ssl_crecv);\n    } else {\n        tcp_sent(pcb, NULL);\n        tcp_poll(pcb, NULL, 0);\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_sslclient_sent\n * Description  : Data has been sent and acknowledged by the remote host.\n *                This means that more data can be sent.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb for which data has been acknowledged\n *                len -- The amount of bytes acknowledged\n * Returns      : ERR_OK: try to send some data by calling tcp_output\n *                ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_ssl_csent(void *arg, struct tcp_pcb *pcb, u16_t len)\n{\n\tespconn_msg *psent = arg;\n    ssl_msg *pssl = psent->pssl;\n    psent->pcommon.pcb = pcb;\n    if (pssl->quiet == true) {\n    \tint pkt_size = pssl->ssl->bm_index + SSL_RECORD_SIZE;\n    \tu16_t max_len = 2 * pcb->mss;\n    \tpssl->pkt_length += len;\n    \tssl_printf(\"espconn_ssl_csent %d %d %d\\n\", len, pssl->pkt_length, pkt_size);\n    \tif (pssl->pkt_length == pkt_size){\n    \t\tpssl->ssl->bm_index = 0;\n    \t\tpssl->pkt_length = 0;\n    \t\tif (psent->pcommon.cntr == 0) {\n    \t\t\tpsent->pespconn->state = ESPCONN_CONNECT;\n    \t\t\tif (psent->pespconn->sent_callback != NULL) {\n    \t\t\t\tpsent->pespconn->sent_callback(psent->pespconn);\n    \t\t\t}\n    \t\t} else {\n    \t\t\tespconn_ssl_sent(psent, psent->pcommon.ptrbuf, psent->pcommon.cntr);\n    \t\t}\n    \t} else {\n    \t\tif (len == max_len){\n    \t\t\tespconn_sent_packet(pcb, &pssl->ssl->bm_all_data[pssl->pkt_length], pkt_size - pssl->pkt_length);\n    \t\t}\n    \t}\n\n    } else {\n    \tssl_printf(\"espconn_ssl_csent %p %p %d\\n\", pcb, pssl->ssl->bm_all_data, len);\n    }\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_sslclient_recv\n * Description  : Data has been received on this pcb.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb which received data\n *                p -- The received data (or NULL when the connection has been closed!)\n *                err -- An error code if there has been an error receiving\n * Returns      : ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_ssl_crecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\n{\n    u16_t ret = 0;\n    espconn_msg *precv = arg;\n    ssl_msg *pssl = precv->pssl;\n    ssl_printf(\"espconn_ssl_crecv %d %p %p\\n\", __LINE__, pssl->ssl, p);\n\n    if (p != NULL) {\n        tcp_recved(pcb, p ->tot_len);\n\n        if (pssl->ssl == NULL) {\n            pbuf_free(p);\n        } else {\n            pssl->ssl->ssl_pbuf = p;\n\n            if (ssl_handshake_status(pssl->ssl) != SSL_OK) {\n                ret = ssl_read(pssl->ssl, NULL);\n                pbuf_free(p);\n                if (ret != SSL_OK){\n                    os_printf(\"client handshake failed\\n\");\n                    espconn_ssl_cclose(arg, pcb);\n                }\n            }\n\n            if (ssl_handshake_status(pssl->ssl) == SSL_OK) {\n                if (!pssl->quiet) {\n                \tssl_printf(\"client handshake need size %d\\n\", system_get_free_heap_size());\n                    const char *common_name = ssl_get_cert_dn(pssl->ssl,\n                                              SSL_X509_CERT_COMMON_NAME);\n\n                    if (common_name) {\n                        ssl_printf(\"Common Name:\\t\\t\\t%s\\n\", common_name);\n                    }\n\n                    display_session_id(pssl->ssl);\n                    display_cipher(pssl->ssl);\n                    pssl->quiet = true;\n                    os_printf(\"client handshake ok!\\n\");\n                    REG_CLR_BIT(0x3ff00014, BIT(0));\n                    os_update_cpu_frequency(80);\n                    precv->pespconn->state = ESPCONN_CONNECT;\n                    precv->pcommon.pcb = pcb;\n                    pbuf_free(p);\n\n                    if (precv->pespconn->proto.tcp->connect_callback != NULL) {\n                    \tprecv->pespconn->proto.tcp->connect_callback(precv->pespconn);\n                    }\n                } else {\n                    uint8_t *read_buf = NULL;\n                    ret = ssl_read(pssl->ssl, &read_buf);\n                    precv->pespconn->state = ESPCONN_READ;\n                    precv->pcommon.pcb = pcb;\n                    pbuf_free(p);\n\n                    if (precv->pespconn->recv_callback != NULL && read_buf != NULL) {\n                    \tprecv->pespconn->recv_callback(precv->pespconn, read_buf, ret);\n                    }\n\n                    precv->pespconn->state = ESPCONN_CONNECT;\n                }\n            }\n        }\n\n    }\n\n    if (err == ERR_OK && p == NULL) {\n        espconn_ssl_cclose(precv, pcb);\n    }\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_client_err\n * Description  : The pcb had an error and is already deallocated.\n *                The argument might still be valid (if != NULL).\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                err -- Error code to indicate why the pcb has been closed\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_ssl_cerr(void *arg, err_t err)\n{\n\tespconn_msg *pssl_cerr = arg;\n\tstruct tcp_pcb *pcb = NULL;\n    LWIP_UNUSED_ARG(err);\n\n    if (pssl_cerr != NULL) {\n    \tos_timer_disarm(&pssl_cerr->pcommon.ptimer);\n        pcb = pssl_cerr->pcommon.pcb;\n        pssl_cerr->pespconn->state = ESPCONN_CLOSE;\n        espconn_printf(\"espconn_ssl_cerr %d %d %d\\n\", pcb->state, pcb->nrtx, err);\n\n        /*remove the node from the client's active connection list*/\n        espconn_list_delete(&plink_active, pssl_cerr);\n\n\n        if (err == ERR_ABRT) {\n        \tswitch (pcb->state) {\n        \t\tcase SYN_SENT:\n        \t\t\tif (pcb->nrtx == TCP_SYNMAXRTX) {\n        \t\t\t\tpssl_cerr->pcommon.err = ESPCONN_CONN;\n        \t\t\t} else {\n        \t\t\t\tpssl_cerr->pcommon.err = err;\n        \t\t\t}\n\n        \t\t\tbreak;\n\n        \t\tcase ESTABLISHED:\n        \t\t\tif (pcb->nrtx == TCP_MAXRTX) {\n        \t\t\t\tpssl_cerr->pcommon.err = ESPCONN_TIMEOUT;\n        \t\t\t} else {\n        \t\t\t\tpssl_cerr->pcommon.err = err;\n        \t\t\t}\n\n        \t\t\tbreak;\n\n        \t\tcase FIN_WAIT_1:\n        \t\t\tif (pcb->nrtx == TCP_MAXRTX) {\n        \t\t\t\tpssl_cerr->pcommon.err = ESPCONN_CLSD;\n        \t\t\t} else {\n        \t\t\t\tpssl_cerr->pcommon.err = err;\n        \t\t\t}\n        \t\t\tbreak;\n        \t\tcase FIN_WAIT_2:\n        \t\t\tpssl_cerr->pcommon.err = ESPCONN_CLSD;\n        \t\t\tbreak;\n        \t\tcase CLOSED:\n        \t\t\tpssl_cerr->pcommon.err = ESPCONN_CONN;\n        \t\t\tbreak;\n        \t\tdefault :\n        \t\t\tbreak;\n        \t}\n        } else {\n        \tpssl_cerr->pcommon.err = err;\n        }\n\n        os_timer_setfn(&pssl_cerr->pcommon.ptimer, espconn_ssl_reconnect, pssl_cerr);\n        os_timer_arm(&pssl_cerr->pcommon.ptimer, 10, 0);\n    }\n}\n\n#if 0\n/******************************************************************************\n * FunctionName : espconn_ssl_cpoll\n * Description  : The poll function is called every 3nd second.\n * If there has been no data sent (which resets the retries) in 3 seconds, close.\n * If the last portion of a file has not been sent in 3 seconds, close.\n *\n * This could be increased, but we don't want to waste resources for bad connections.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb for which data has been acknowledged\n * Returns      : ERR_OK: try to send some data by calling tcp_output\n *                ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_ssl_cpoll(void *arg, struct tcp_pcb *pcb)\n{\n    ssl_printf(\"espconn_ssl_cpoll %p %d\\n\", pcb, pcb->state);\n    struct espconn *espconn = arg;\n\n    if (arg == NULL) {\n        tcp_abandon(pcb, 0);\n        tcp_poll(pcb, NULL, 0);\n        return ERR_ABRT;\n    }\n\n    if (pcb ->state == ESTABLISHED) {\n    \tespconn->recv_check ++;\n    \tif (espconn ->recv_check == 0x05){\n\t\t\t//tcp_poll(pcb, espconn_ssl_cpoll, 0);\n\t\t\tespconn->recv_check = 0;\n\t\t\tespconn_ssl_cclose(arg, pcb);\n    \t}\n    } else {\n        //tcp_poll(pcb, espconn_ssl_cpoll, 0);\n        espconn_ssl_cclose(arg, pcb);\n    }\n\n    return ERR_OK;\n}\n#endif\n/******************************************************************************\n * FunctionName : espconn_sslclient_connect\n * Description  : A new incoming connection has been connected.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                tpcb -- The connection pcb which is connected\n *                err -- An unused error code, always ERR_OK currently\n * Returns      : connection result\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_ssl_connect(void *arg, struct tcp_pcb *tpcb, err_t err)\n{\n\tespconn_msg *pconnect = arg;\n    ssl_msg *pssl = NULL;\n    uint32_t options;\n    options = SSL_SERVER_VERIFY_LATER | SSL_DISPLAY_CERTS | SSL_NO_DEFAULT_KEY;\n    ssl_printf(\"espconn_ssl_connect %p %p %p %d\\n\", tpcb, arg, pespconn->psecure, system_get_free_heap_size());\n\n    //if (pespconn->psecure != NULL){\n    //    return ERR_ISCONN;\n    //}\n\n    pconnect->pcommon.pcb = tpcb;\n    pssl = (ssl_msg *)os_zalloc(sizeof(ssl_msg));\n    pconnect->pssl = pssl;\n\n    if (pssl == NULL) {\n        return ERR_MEM;\n    }\n\n    REG_SET_BIT(0x3ff00014, BIT(0));\n    os_update_cpu_frequency(160);\n    os_printf(\"client handshake start.\\n\");\n    pssl->quiet = false;\n    pssl->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS);\n\n    if (pssl->ssl_ctx == NULL) {\n        return ERR_MEM;\n    }\n\n    ssl_printf(\"espconn_ssl_client ssl_ctx %p\\n\", pssl->ssl_ctx);\n    pssl->ssl = SSLClient_new(pssl->ssl_ctx, tpcb, NULL, 0);\n\n    if (pssl->ssl == NULL) {\n        return ERR_MEM;\n    }\n\n    tcp_arg(tpcb, arg);\n    tcp_sent(tpcb, espconn_ssl_csent);\n    tcp_recv(tpcb, espconn_ssl_crecv);\n    //tcp_poll(tpcb, espconn_ssl_cpoll, 6);\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_ssl_disconnect\n * Description  : A new incoming connection has been disconnected.\n * Parameters   : espconn -- the espconn used to disconnect with host\n * Returns      : none\n*******************************************************************************/\nvoid ICACHE_FLASH_ATTR espconn_ssl_disconnect(espconn_msg *pdis)\n{\n    if (pdis != NULL) {\n    \tif (pdis->preverse == NULL)\n    \t\tespconn_ssl_cclose(pdis, pdis->pcommon.pcb);\n    \telse\n    \t\tespconn_ssl_sclose(pdis, pdis->pcommon.pcb);\n    } else {\n        ssl_printf(\"espconn_ssl_disconnect err.\\n\");\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_ssl_client\n * Description  : Initialize the client: set up a connect PCB and bind it to\n *                the defined port\n * Parameters   : espconn -- the espconn used to build client\n * Returns      : none\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR\nespconn_ssl_client(struct espconn *espconn)\n{\n    struct tcp_pcb *pcb;\n    struct ip_addr ipaddr;\n    espconn_msg *pclient = NULL;\n    pclient = plink_active;\n    while(pclient != NULL){\n    \tif (pclient->pssl != NULL)\n    \t\treturn ESPCONN_ISCONN;\n\n    \tpclient = pclient->pnext;\n    }\n    pclient = (espconn_msg *)os_zalloc(sizeof(espconn_msg));\n    if (pclient == NULL){\n    \treturn ESPCONN_MEM;\n\t}\n    IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0],\n             espconn->proto.tcp->remote_ip[1],\n             espconn->proto.tcp->remote_ip[2],\n             espconn->proto.tcp->remote_ip[3]);\n    pcb = tcp_new();\n    if (pcb == NULL) {\n        espconn ->state = ESPCONN_NONE;\n        os_free(pclient);\n        pclient = NULL;\n        return ESPCONN_MEM;\n    } else {\n    \t/*insert the node to the active connection list*/\n    \tespconn_list_creat(&plink_active, pclient);\n    \ttcp_arg(pcb, (void *)pclient);\n    \ttcp_err(pcb, espconn_ssl_cerr);\n    \tpclient->preverse = NULL;\n    \tpclient->pespconn = espconn;\n    \tpclient->pespconn->state = ESPCONN_WAIT;\n    \tpclient->pcommon.pcb = pcb;\n        tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port);\n        pclient->pcommon.err = tcp_connect(pcb, &ipaddr, pclient->pespconn->proto.tcp->remote_port, espconn_ssl_connect);\n        return ESPCONN_OK;\n    }\n}\n\n/////////////////////////////server's function/////////////////////////////////\n/******************************************************************************\n * FunctionName : espconn_ssl_sclose_cb\n * Description  : as\n * Parameters   :\n * Returns      :\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_ssl_sclose_cb(void *arg)\n{\n    static uint16 timecount = 0;\n    espconn_msg *psclose_cb = arg;\n\n    if (psclose_cb == NULL) {\n        return;\n    }\n\n    struct tcp_pcb *pcb = psclose_cb->pcommon.pcb;\n\n    ssl_printf(\"espconn_ssl_sclose_cb %d %d\\n\", pcb->state, pcb->nrtx);\n\n    if (pcb->state == CLOSED || pcb->state == TIME_WAIT) {\n    \tpsclose_cb ->pespconn ->state = ESPCONN_CLOSE;\n    \tpsclose_cb->pespconn->link_cnt --;\n    \t/*remove the node from the server's active connection list*/\n    \tespconn_list_delete(&plink_active, psclose_cb);\n        espconn_ssl_dissuccessful((void *)psclose_cb);\n    } else {\n    \tos_timer_arm(&psclose_cb->pcommon.ptimer, TCP_FAST_INTERVAL, 0);\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_sslclient_close\n * Description  : The connection shall be actively closed.\n * Parameters   : pcb -- Additional argument to pass to the callback function\n *                pcb -- the pcb to close\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_ssl_sclose(void *arg, struct tcp_pcb *pcb)\n{\n    espconn_msg *psclose = arg;\n\n    os_timer_disarm(&psclose->pcommon.ptimer);\n    os_timer_setfn(&psclose->pcommon.ptimer, espconn_ssl_sclose_cb, psclose);\n    os_timer_arm(&psclose->pcommon.ptimer, TCP_FAST_INTERVAL, 0);\n    tcp_recv(pcb, NULL);\n    psclose->pcommon.err = tcp_close(pcb);\n\n    if (psclose->pcommon.err != ERR_OK) {\n        /* closing failed, try again later */\n        tcp_recv(pcb, espconn_ssl_srecv);\n    } else {\n        tcp_sent(pcb, NULL);\n        tcp_poll(pcb, NULL, 0);\n    }\n}\n\n\n/******************************************************************************\n * FunctionName : espconn_sslclient_sent\n * Description  : Data has been sent and acknowledged by the remote host.\n *                This means that more data can be sent.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb for which data has been acknowledged\n *                len -- The amount of bytes acknowledged\n * Returns      : ERR_OK: try to send some data by calling tcp_output\n *                ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_ssl_ssent(void *arg, struct tcp_pcb *pcb, u16_t len)\n{\n\tespconn_msg *psent = arg;\n    ssl_msg *pssl = psent->pssl;\n    psent->pcommon.pcb = pcb;\n    psent->pcommon.recv_check = 0;\n    if (ssl_handshake_status(pssl->ssl) == SSL_OK) {\n        if (!pssl->quiet) {\n           ssl_printf(\"espconn_ssl_ssent %p %d\\n\",pcb, system_get_free_heap_size());\n           const char *common_name = ssl_get_cert_dn(pssl->ssl, SSL_X509_CERT_COMMON_NAME);\n\n           if (common_name) {\n              ssl_printf(\"Common Name:\\t\\t\\t%s\\n\", common_name);\n           }\n\n           display_session_id(pssl->ssl);\n           display_cipher(pssl->ssl);\n           pssl->quiet = true;\n           os_printf(\"server handshake ok!\\n\");\n           REG_CLR_BIT(0x3ff00014, BIT(0));\n           os_update_cpu_frequency(80);\n           psent->pespconn->state = ESPCONN_CONNECT;\n\n           if (psent->pespconn->proto.tcp->connect_callback != NULL) {\n        \t   psent->pespconn->proto.tcp->connect_callback(psent->pespconn);\n           }\n       } else {\n\n    \t   int pkt_size = pssl->ssl->bm_index + SSL_RECORD_SIZE;\n    \t   u16_t max_len = 2 * pcb->mss;\n    \t   pssl->pkt_length += len;\n    \t   ssl_printf(\"espconn_ssl_ssent %d %d %d\\n\", len, pssl->pkt_length, pkt_size);\n    \t   if (pssl->pkt_length == pkt_size){\n    \t\t   pssl->ssl->bm_index = 0;\n    \t\t   pssl->pkt_length = 0;\n    \t       if (psent->pcommon.cntr == 0) {\n    \t    \t   psent->pespconn->state = ESPCONN_CONNECT;\n    \t    \t   if (psent->pespconn->sent_callback != NULL) {\n    \t    \t\t   psent->pespconn->sent_callback(psent->pespconn);\n    \t    \t   }\n    \t       } else {\n    \t    \t   espconn_ssl_sent(psent, psent->pcommon.ptrbuf, psent->pcommon.cntr);\n    \t       }\n    \t   } else {\n    \t\t   if (len == max_len){\n    \t\t\t   espconn_sent_packet(pcb, &pssl->ssl->bm_all_data[pssl->pkt_length], pkt_size - pssl->pkt_length);\n    \t\t   }\n    \t   }\n       }\n    } else {\n    \tssl_printf(\"espconn_ssl_ssent %p %p %d\\n\",pcb, pssl->ssl->bm_all_data, len);\n    }\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_sslclient_recv\n * Description  : Data has been received on this pcb.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb which received data\n *                p -- The received data (or NULL when the connection has been closed!)\n *                err -- An error code if there has been an error receiving\n * Returns      : ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_ssl_srecv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\n{\n    u16_t ret = 0;\n    espconn_msg *precv = arg;\n    ssl_msg *pssl = precv->pssl;\n    ssl_printf(\"espconn_ssl_srecv %d %p %p\\n\", __LINE__, pcb, p);\n\n    if (p != NULL) {\n        tcp_recved(pcb, p ->tot_len);\n        precv->pcommon.recv_check = 0;\n        if (pssl->ssl == NULL) {\n            pbuf_free(p);\n        } else {\n            pssl->ssl->ssl_pbuf = p;\n\n            if (ssl_handshake_status(pssl->ssl) != SSL_OK) {\n                ret = ssl_read(pssl->ssl, NULL);\n                pbuf_free(p);\n                if (ret != SSL_OK){\n                \tos_printf(\"server handshake failed.\\n\");\n                \tespconn_ssl_sclose(arg, pcb);\n                }\n            } else {\n                    uint8_t *read_buf = NULL;\n                    ret = ssl_read(pssl->ssl, &read_buf);\n                    precv->pespconn->state = ESPCONN_READ;\n                    precv->pcommon.pcb = pcb;\n                    pbuf_free(p);\n\n                    if (precv->pespconn->recv_callback != NULL && read_buf != NULL) {\n                    \tprecv->pespconn->recv_callback(precv->pespconn, read_buf, ret);\n                    }\n\n                    precv->pespconn->state = ESPCONN_CONNECT;\n                }\n\n        }\n\n    }\n\n    if (err == ERR_OK && p == NULL) {\n        espconn_ssl_sclose(precv, pcb);\n    }\n\n    return ERR_OK;\n}\n\n\n/******************************************************************************\n * FunctionName : espconn_server_poll\n * Description  : The poll function is called every 3nd second.\n * If there has been no data sent (which resets the retries) in 3 seconds, close.\n * If the last portion of a file has not been sent in 3 seconds, close.\n *\n * This could be increased, but we don't want to waste resources for bad connections.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb for which data has been acknowledged\n * Returns      : ERR_OK: try to send some data by calling tcp_output\n *                ERR_ABRT: if you have called tcp_abort from within the function!\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_ssl_spoll(void *arg, struct tcp_pcb *pcb)\n{\n    ssl_printf(\"espconn_ssl_spoll %p %d\\n\", pcb, pcb->state);\n    espconn_msg *pspoll = arg;\n    if (arg == NULL) {\n        tcp_abandon(pcb, 0);\n        tcp_poll(pcb, NULL, 0);\n        return ERR_ABRT;\n    }\n\n    if (pcb ->state == ESTABLISHED) {\n    \tpspoll ->pcommon.recv_check ++;\n    \tif (pspoll ->pcommon.recv_check == pspoll ->pcommon.timeout){\n\t\t\ttcp_poll(pcb, NULL, 0);\n    \t\tpspoll ->pcommon.recv_check = 0;\n\t\t\tespconn_ssl_sclose(arg, pcb);\n    \t}\n    } else {\n    \ttcp_poll(pcb, NULL, 0);\n        espconn_ssl_sclose(arg, pcb);\n    }\n\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : esponn_server_err\n * Description  : The pcb had an error and is already deallocated.\n *                The argument might still be valid (if != NULL).\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                err -- Error code to indicate why the pcb has been closed\n * Returns      : none\n*******************************************************************************/\nstatic void ICACHE_FLASH_ATTR\nespconn_ssl_serr(void *arg, err_t err)\n{\n\tespconn_msg *pserr = arg;\n\tstruct tcp_pcb *pcb = NULL;\n    LWIP_UNUSED_ARG(err);\n\n    if (pserr != NULL) {\n    \tos_timer_disarm(&pserr->pcommon.ptimer);\n        pcb = pserr->pcommon.pcb;\n        pserr->pespconn->state = ESPCONN_CLOSE;\n\n        /*remove the node from the server's active connection list*/\n        espconn_list_delete(&plink_active, pserr);\n\n        if (err == ERR_ABRT) {\n        \tswitch (pcb->state) {\n        \t\tcase SYN_RCVD:\n        \t\t\tif (pcb->nrtx == TCP_SYNMAXRTX) {\n        \t\t\t\tpserr->pcommon.err = ESPCONN_CONN;\n        \t\t\t} else {\n        \t\t\t\tpserr->pcommon.err = err;\n        \t\t\t}\n\n        \t\t\tbreak;\n\n        \t\tcase ESTABLISHED:\n        \t\t\tif (pcb->nrtx == TCP_MAXRTX) {\n        \t\t\t\tpserr->pcommon.err = ESPCONN_TIMEOUT;\n        \t\t\t} else {\n        \t\t\t\tpserr->pcommon.err = err;\n        \t\t\t}\n\n        \t\t\tbreak;\n\n        \t\tcase CLOSE_WAIT:\n        \t\t\tif (pcb->nrtx == TCP_MAXRTX) {\n        \t\t\t\tpserr->pcommon.err = ESPCONN_CLSD;\n        \t\t\t} else {\n        \t\t\t\tpserr->pcommon.err = err;\n        \t\t\t}\n        \t\t\tbreak;\n        \t\tcase LAST_ACK:\n        \t\t\tpserr->pcommon.err = ESPCONN_CLSD;\n        \t\t\tbreak;\n        \t\tcase CLOSED:\n        \t\t\tpserr->pcommon.err = ESPCONN_CONN;\n        \t\t\tbreak;\n        \t\tdefault :\n        \t\t\tbreak;\n        \t}\n        } else {\n        \tpserr->pcommon.err = err;\n        }\n\n        os_timer_setfn(&pserr->pcommon.ptimer, espconn_ssl_reconnect, pserr);\n        os_timer_arm(&pserr->pcommon.ptimer, 10, 0);\n    }\n}\n\n/******************************************************************************\n * FunctionName : espconn_tcp_accept\n * Description  : A new incoming connection has been accepted.\n * Parameters   : arg -- Additional argument to pass to the callback function\n *                pcb -- The connection pcb which is accepted\n *                err -- An unused error code, always ERR_OK currently\n * Returns      : acception result\n*******************************************************************************/\nstatic err_t ICACHE_FLASH_ATTR\nespconn_ssl_accept(void *arg, struct tcp_pcb *pcb, err_t err)\n{\n    struct espconn *espconn = arg;\n    ssl_msg *pssl = NULL;\n    espconn_msg *paccept = NULL;\n    remot_info *pinfo = NULL;\n    ssl_printf(\"espconn_ssl_accept %p %p %p %d\\n\", pcb, arg, espconn->psecure, system_get_free_heap_size());\n    LWIP_UNUSED_ARG(err);\n\n\tpaccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg));\n\ttcp_arg(pcb, paccept);\n\ttcp_err(pcb, espconn_ssl_serr);\n\tif (paccept == NULL)\n\t\treturn ERR_MEM;\n\t/*insert the node to the active connection list*/\n\tespconn_list_creat(&plink_active, paccept);\n\tpaccept->preverse = espconn;\n\tpaccept->pespconn = espconn;\n\n\tpaccept->pcommon.timeout = 0x0a;\n\tpaccept->pcommon.pcb = pcb;\n\tpaccept->pcommon.remote_port = pcb->remote_port;\n\tpaccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip);\n\tpaccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip);\n\tpaccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip);\n\tpaccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip);\n\tos_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4);\n\tespconn->proto.tcp->remote_port = pcb->remote_port;\n\n\tespconn_get_connection_info(espconn, &pinfo , ESPCONN_SSL);\n\tif (espconn->link_cnt == 0x01)\n\t\treturn ERR_ISCONN;\n\n    pssl = (ssl_msg *)os_zalloc(sizeof(ssl_msg));\n    paccept->pssl = pssl;\n    if (pssl == NULL) {\n        return ERR_MEM;\n    }\n\n    REG_SET_BIT(0x3ff00014, BIT(0));\n    os_update_cpu_frequency(160);\n    os_printf(\"server handshake start.\\n\");\n    pssl->quiet = false;\n    pssl->ssl_ctx = ssl_ctx_new(SSL_DISPLAY_CERTS, SSL_DEFAULT_SVR_SESS);\n\n    if (pssl->ssl_ctx == NULL) {\n        ssl_printf(\"Error: Server context is invalid\\n\");\n        return ERR_MEM;\n    }\n\n    ssl_printf(\"Server context %p\\n\", pssl->ssl_ctx);\n    pssl->ssl = sslserver_new(pssl->ssl_ctx, pcb);\n\n    if (pssl->ssl == NULL) {\n        ssl_printf(\"Error: Server ssl connection is invalid\\n\");\n        return ERR_MEM;\n\n    }\n\n    tcp_sent(pcb, espconn_ssl_ssent);\n    tcp_recv(pcb, espconn_ssl_srecv);\n    tcp_poll(pcb, espconn_ssl_spoll, 2);\n    return ERR_OK;\n}\n\n/******************************************************************************\n * FunctionName : espconn_ssl_server\n * Description  : as\n * Parameters   :\n * Returns      :\n*******************************************************************************/\nsint8 ICACHE_FLASH_ATTR espconn_ssl_server(struct espconn *espconn)\n{\n    struct tcp_pcb *pcb;\n\n    pcb = tcp_new();\n    if (pcb == NULL) {\n        espconn ->state = ESPCONN_NONE;\n        return ESPCONN_MEM;\n    } else {\n        tcp_bind(pcb, IP_ADDR_ANY, espconn->proto.tcp->local_port);\n        pcb = tcp_listen(pcb);\n        if (pcb != NULL) {\n            espconn ->state = ESPCONN_LISTEN;\n            tcp_arg(pcb, (void *)espconn);\n            tcp_accept(pcb, espconn_ssl_accept);\n            return ESPCONN_OK;\n        } else {\n            espconn ->state = ESPCONN_NONE;\n            return ESPCONN_MEM;\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "app/ssl/crypto/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\n\nGEN_LIBS = libsslcrypto.a\n\nendif\n\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/ssl/crypto/ssl_aes.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * AES implementation - this is a small code version. There are much faster\n * versions around but they are much larger in size (i.e. they use large \n * submix tables).\n */\n\n//#include <string.h>\n#include \"lwip/opt.h\"\n\n#include \"lwip/def.h\"\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto.h\"\n\n/* all commented out in skeleton mode */\n#ifndef CONFIG_SSL_SKELETON_MODE\n\n#define rot1(x) (((x) << 24) | ((x) >> 8))\n#define rot2(x) (((x) << 16) | ((x) >> 16))\n#define rot3(x) (((x) <<  8) | ((x) >> 24))\n\n/* \n * This cute trick does 4 'mul by two' at once.  Stolen from\n * Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is\n * a standard graphics trick\n * The key to this is that we need to xor with 0x1b if the top bit is set.\n * a 1xxx xxxx   0xxx 0xxx First we mask the 7bit,\n * b 1000 0000   0000 0000 then we shift right by 7 putting the 7bit in 0bit,\n * c 0000 0001   0000 0000 we then subtract (c) from (b)\n * d 0111 1111   0000 0000 and now we and with our mask\n * e 0001 1011   0000 0000\n */\n#define mt  0x80808080\n#define ml  0x7f7f7f7f\n#define mh  0xfefefefe\n#define mm  0x1b1b1b1b\n#define mul2(x,t)\t((t)=((x)&mt), \\\n\t\t\t((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))\n\n#define inv_mix_col(x,f2,f4,f8,f9) (\\\n\t\t\t(f2)=mul2(x,f2), \\\n\t\t\t(f4)=mul2(f2,f4), \\\n\t\t\t(f8)=mul2(f4,f8), \\\n\t\t\t(f9)=(x)^(f8), \\\n\t\t\t(f8)=((f2)^(f4)^(f8)), \\\n\t\t\t(f2)^=(f9), \\\n\t\t\t(f4)^=(f9), \\\n\t\t\t(f8)^=rot3(f2), \\\n\t\t\t(f8)^=rot2(f4), \\\n\t\t\t(f8)^rot1(f9))\n\n/*\n * AES S-box\n */\nstatic const uint8_t aes_sbox[256] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR =\n{\n\t0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,\n\t0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,\n\t0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,\n\t0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,\n\t0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,\n\t0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,\n\t0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,\n\t0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,\n\t0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,\n\t0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,\n\t0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,\n\t0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,\n\t0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,\n\t0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,\n\t0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,\n\t0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,\n\t0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,\n\t0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,\n\t0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,\n\t0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,\n\t0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,\n\t0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,\n\t0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,\n\t0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,\n\t0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,\n\t0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,\n\t0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,\n\t0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,\n\t0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,\n\t0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,\n\t0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,\n\t0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,\n};\n\n/*\n * AES is-box\n */\nstatic const uint8_t aes_isbox[256] ICACHE_STORE_ATTR ICACHE_RODATA_ATTR = \n{\n    0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,\n    0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,\n    0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,\n    0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,\n    0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,\n    0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,\n    0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,\n    0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,\n    0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,\n    0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,\n    0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,\n    0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,\n    0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,\n    0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,\n    0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,\n    0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,\n    0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,\n    0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,\n    0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,\n    0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,\n    0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,\n    0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,\n    0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,\n    0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,\n    0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,\n    0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,\n    0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,\n    0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,\n    0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,\n    0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,\n    0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,\n    0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d\n};\n\nstatic const unsigned char Rcon[30]=\n{\n\t0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,\n\t0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,\n\t0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,\n\t0xb3,0x7d,0xfa,0xef,0xc5,0x91,\n};\n\n/* ----- static functions ----- */\nstatic void AES_encrypt(const AES_CTX *ctx, uint32_t *data);\nstatic void AES_decrypt(const AES_CTX *ctx, uint32_t *data);\n\n/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial\n   x^8+x^4+x^3+x+1 */\nstatic unsigned char ICACHE_FLASH_ATTR AES_xtime(uint32_t x)\n{\n\treturn (x&0x80) ? (x<<1)^0x1b : x<<1;\n}\n\n/**\n * Set up AES with the key/iv and cipher size.\n */\nvoid ICACHE_FLASH_ATTR AES_set_key(AES_CTX *ctx, const uint8_t *key, \n        const uint8_t *iv, AES_MODE mode)\n{\n    int i, ii;\n    uint32_t *W, tmp, tmp2;\n    const unsigned char *ip;\n    int words;\n\n    switch (mode)\n    {\n        case AES_MODE_128:\n            i = 10;\n            words = 4;\n            break;\n\n        case AES_MODE_256:\n            i = 14;\n            words = 8;\n            break;\n\n        default:        /* fail silently */\n            return;\n    }\n\n    ctx->rounds = i;\n    ctx->key_size = words;\n    W = ctx->ks;\n    for (i = 0; i < words; i+=2)\n    {\n        W[i+0]=\t((uint32_t)key[ 0]<<24)|\n            ((uint32_t)key[ 1]<<16)|\n            ((uint32_t)key[ 2]<< 8)|\n            ((uint32_t)key[ 3]    );\n        W[i+1]=\t((uint32_t)key[ 4]<<24)|\n            ((uint32_t)key[ 5]<<16)|\n            ((uint32_t)key[ 6]<< 8)|\n            ((uint32_t)key[ 7]    );\n        key += 8;\n    }\n\n    ip = Rcon;\n    ii = 4 * (ctx->rounds+1);\n    for (i = words; i<ii; i++)\n    {\n        tmp = W[i-1];\n\n        if ((i % words) == 0)\n        {\n            // tmp2 =(uint32_t)aes_sbox[(tmp    )&0xff]<< 8;\n            // tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;\n            // tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;\n            // tmp2|=(uint32_t)aes_sbox[(tmp>>24)     ];\n            tmp2 =((uint32_t)byte_of_aligned_array(aes_sbox,(tmp    )&0xff))<< 8;\n            tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>> 8)&0xff))<<16;\n            tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>>16)&0xff))<<24;\n            tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>>24)     ));\n            tmp=tmp2^(((unsigned int)*ip)<<24);\n            ip++;\n        }\n\n        if ((words == 8) && ((i % words) == 4))\n        {\n            // tmp2 =(uint32_t)aes_sbox[(tmp    )&0xff]    ;\n            // tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;\n            // tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;\n            // tmp2|=(uint32_t)aes_sbox[(tmp>>24)     ]<<24;\n            tmp2 =((uint32_t)byte_of_aligned_array(aes_sbox,(tmp    )&0xff))    ;\n            tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>> 8)&0xff))<< 8;\n            tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>>16)&0xff))<<16;\n            tmp2|=((uint32_t)byte_of_aligned_array(aes_sbox,(tmp>>24)     ))<<24;\n            tmp=tmp2;\n        }\n\n        W[i]=W[i-words]^tmp;\n    }\n\n    /* copy the iv across */\n    os_memcpy(ctx->iv, iv, 16);\n}\n\n/**\n * Change a key for decryption.\n */\nvoid ICACHE_FLASH_ATTR AES_convert_key(AES_CTX *ctx)\n{\n    int i;\n    uint32_t *k,w,t1,t2,t3,t4;\n\n    k = ctx->ks;\n    k += 4;\n\n    for (i= ctx->rounds*4; i > 4; i--)\n    {\n        w= *k;\n        w = inv_mix_col(w,t1,t2,t3,t4);\n        *k++ =w;\n    }\n}\n\n/**\n * Encrypt a byte sequence (with a block size 16) using the AES cipher.\n */\nvoid ICACHE_FLASH_ATTR AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)\n{\n    int i;\n    uint32_t tin[4], tout[4], iv[4];\n\n    os_memcpy(iv, ctx->iv, AES_IV_SIZE);\n    for (i = 0; i < 4; i++)\n        tout[i] = ntohl(iv[i]);\n\n    for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)\n    {\n        uint32_t msg_32[4];\n        uint32_t out_32[4];\n        os_memcpy(msg_32, msg, AES_BLOCKSIZE);\n        msg += AES_BLOCKSIZE;\n\n        for (i = 0; i < 4; i++)\n            tin[i] = ntohl(msg_32[i])^tout[i];\n\n        AES_encrypt(ctx, tin);\n\n        for (i = 0; i < 4; i++)\n        {\n            tout[i] = tin[i]; \n            out_32[i] = htonl(tout[i]);\n        }\n\n        os_memcpy(out, out_32, AES_BLOCKSIZE);\n        out += AES_BLOCKSIZE;\n    }\n\n    for (i = 0; i < 4; i++)\n        iv[i] = htonl(tout[i]);\n    os_memcpy(ctx->iv, iv, AES_IV_SIZE);\n}\n\n/**\n * Decrypt a byte sequence (with a block size 16) using the AES cipher.\n */\nvoid ICACHE_FLASH_ATTR AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)\n{\n    int i;\n    uint32_t tin[4], xor[4], tout[4], data[4], iv[4];\n\n    os_memcpy(iv, ctx->iv, AES_IV_SIZE);\n    for (i = 0; i < 4; i++)\n        xor[i] = ntohl(iv[i]);\n\n    for (length -= 16; length >= 0; length -= 16)\n    {\n        uint32_t msg_32[4];\n        uint32_t out_32[4];\n        os_memcpy(msg_32, msg, AES_BLOCKSIZE);\n        msg += AES_BLOCKSIZE;\n\n        for (i = 0; i < 4; i++)\n        {\n            tin[i] = ntohl(msg_32[i]);\n            data[i] = tin[i];\n        }\n\n        AES_decrypt(ctx, data);\n\n        for (i = 0; i < 4; i++)\n        {\n            tout[i] = data[i]^xor[i];\n            xor[i] = tin[i];\n            out_32[i] = htonl(tout[i]);\n        }\n\n        os_memcpy(out, out_32, AES_BLOCKSIZE);\n        out += AES_BLOCKSIZE;\n    }\n\n    for (i = 0; i < 4; i++)\n        iv[i] = htonl(xor[i]);\n    os_memcpy(ctx->iv, iv, AES_IV_SIZE);\n}\n\n/**\n * Encrypt a single block (16 bytes) of data\n */\nstatic void ICACHE_FLASH_ATTR AES_encrypt(const AES_CTX *ctx, uint32_t *data)\n{\n    /* To make this code smaller, generate the sbox entries on the fly.\n     * This will have a really heavy effect upon performance.\n     */\n    uint32_t tmp[4];\n    uint32_t tmp1, old_a0, a0, a1, a2, a3, row;\n    int curr_rnd;\n    int rounds = ctx->rounds; \n    const uint32_t *k = ctx->ks;\n\n    /* Pre-round key addition */\n    for (row = 0; row < 4; row++)\n        data[row] ^= *(k++);\n\n    /* Encrypt one block. */\n    for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)\n    {\n        /* Perform ByteSub and ShiftRow operations together */\n        for (row = 0; row < 4; row++)\n        {\n            // a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];\n            // a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];\n            // a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF]; \n            // a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];\n\n            a0 = (uint32_t)(byte_of_aligned_array(aes_sbox,(data[row%4]>>24)&0xFF));\n            a1 = (uint32_t)(byte_of_aligned_array(aes_sbox,(data[(row+1)%4]>>16)&0xFF));\n            a2 = (uint32_t)(byte_of_aligned_array(aes_sbox,(data[(row+2)%4]>>8)&0xFF)); \n            a3 = (uint32_t)(byte_of_aligned_array(aes_sbox,(data[(row+3)%4])&0xFF));\n\n            /* Perform MixColumn iff not last round */\n            if (curr_rnd < (rounds - 1))\n            {\n                tmp1 = a0 ^ a1 ^ a2 ^ a3;\n                old_a0 = a0;\n                a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);\n                a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);\n                a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);\n                a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);\n            }\n\n            tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);\n        }\n\n        /* KeyAddition - note that it is vital that this loop is separate from\n           the MixColumn operation, which must be atomic...*/ \n        for (row = 0; row < 4; row++)\n            data[row] = tmp[row] ^ *(k++);\n    }\n}\n\n/**\n * Decrypt a single block (16 bytes) of data\n */\nstatic void ICACHE_FLASH_ATTR AES_decrypt(const AES_CTX *ctx, uint32_t *data)\n{ \n    uint32_t tmp[4];\n    uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;\n    uint32_t a0, a1, a2, a3, row;\n    int curr_rnd;\n    int rounds = ctx->rounds;\n    const uint32_t *k = ctx->ks + ((rounds+1)*4);\n\n    /* pre-round key addition */\n    for (row=4; row > 0;row--)\n        data[row-1] ^= *(--k);\n\n    /* Decrypt one block */\n    for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)\n    {\n        /* Perform ByteSub and ShiftRow operations together */\n        for (row = 4; row > 0; row--)\n        {\n            // a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];\n            // a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];\n            // a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];\n            // a3 = aes_isbox[(data[row%4])&0xFF];\n\n            a0 = byte_of_aligned_array(aes_isbox,(data[(row+3)%4]>>24)&0xFF);\n            a1 = byte_of_aligned_array(aes_isbox,(data[(row+2)%4]>>16)&0xFF);\n            a2 = byte_of_aligned_array(aes_isbox,(data[(row+1)%4]>>8)&0xFF);\n            a3 = byte_of_aligned_array(aes_isbox,(data[row%4])&0xFF);\n\n            /* Perform MixColumn iff not last round */\n            if (curr_rnd<(rounds-1))\n            {\n                /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)\n                   are quite large compared to encryption; this \n                   operation slows decryption down noticeably. */\n                xt0 = AES_xtime(a0^a1);\n                xt1 = AES_xtime(a1^a2);\n                xt2 = AES_xtime(a2^a3);\n                xt3 = AES_xtime(a3^a0);\n                xt4 = AES_xtime(xt0^xt1);\n                xt5 = AES_xtime(xt1^xt2);\n                xt6 = AES_xtime(xt4^xt5);\n\n                xt0 ^= a1^a2^a3^xt4^xt6;\n                xt1 ^= a0^a2^a3^xt5^xt6;\n                xt2 ^= a0^a1^a3^xt4^xt6;\n                xt3 ^= a0^a1^a2^xt5^xt6;\n                tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);\n            }\n            else\n                tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);\n        }\n\n        for (row = 4; row > 0; row--)\n            data[row-1] = tmp[row-1] ^ *(--k);\n    }\n}\n\n#endif\n"
  },
  {
    "path": "app/ssl/crypto/ssl_bigint.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @defgroup bigint_api Big Integer API\n * @brief The bigint implementation as used by the axTLS project.\n *\n * The bigint library is for RSA encryption/decryption as well as signing.\n * This code tries to minimise use of malloc/free by maintaining a small \n * cache. A bigint context may maintain state by being made \"permanent\". \n * It be be later released with a bi_depermanent() and bi_free() call.\n *\n * It supports the following reduction techniques:\n * - Classical\n * - Barrett\n * - Montgomery\n *\n * It also implements the following:\n * - Karatsuba multiplication\n * - Squaring\n * - Sliding window exponentiation\n * - Chinese Remainder Theorem (implemented in rsa.c).\n *\n * All the algorithms used are pretty standard, and designed for different\n * data bus sizes. Negative numbers are not dealt with at all, so a subtraction\n * may need to be tested for negativity.\n *\n * This library steals some ideas from Jef Poskanzer\n * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>\n * and GMP <http://www.swox.com/gmp>. It gets most of its implementation\n * detail from \"The Handbook of Applied Cryptography\"\n * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>\n * @{\n */\n\n//#include <stdlib.h>\n//#include <limits.h>\n//#include <string.h>\n//#include <stdio.h>\n//#include <time.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_bigint.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\n\n#define V1      v->comps[v->size-1]                 /**< v1 for division */\n#define V2      v->comps[v->size-2]                 /**< v2 for division */\n#define U(j)    tmp_u->comps[tmp_u->size-j-1]       /**< uj for division */\n#define Q(j)    quotient->comps[quotient->size-j-1] /**< qj for division */\n\nstatic bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);\nstatic bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);\nstatic bigint *alloc(BI_CTX *ctx, int size);\nstatic bigint *trim(bigint *bi);\nstatic void more_comps(bigint *bi, int n);\n#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \\\n    defined(CONFIG_BIGINT_MONTGOMERY)\nstatic bigint *comp_right_shift(bigint *biR, int num_shifts);\nstatic bigint *comp_left_shift(bigint *biR, int num_shifts);\n#endif\n\n#ifdef CONFIG_BIGINT_CHECK_ON\nstatic void check(const bigint *bi);\n#else\n#define check(A)                /**< disappears in normal production mode */\n#endif\n\n\n/**\n * @brief Start a new bigint context.\n * @return A bigint context.\n */\nBI_CTX * ICACHE_FLASH_ATTR bi_initialize(void)\n{\n    /* calloc() sets everything to zero */\n    BI_CTX *ctx = (BI_CTX *)os_zalloc(sizeof(BI_CTX));\n   \n    /* the radix */\n    ctx->bi_radix = alloc(ctx, 2); \n    ctx->bi_radix->comps[0] = 0;\n    ctx->bi_radix->comps[1] = 1;\n    bi_permanent(ctx->bi_radix);\n    return ctx;\n}\n\n/**\n * @brief Close the bigint context and free any resources.\n *\n * Free up any used memory - a check is done if all objects were not \n * properly freed.\n * @param ctx [in]   The bigint session context.\n */\nvoid ICACHE_FLASH_ATTR bi_terminate(BI_CTX *ctx)\n{\n    bi_depermanent(ctx->bi_radix); \n    bi_free(ctx, ctx->bi_radix);\n\n    if (ctx->active_count != 0)\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"bi_terminate: there were %d un-freed bigints\\n\",\n                       ctx->active_count);\n#endif\n        return;     /* wujg : org ---> abort(); */\n    }\n\n    bi_clear_cache(ctx);\n    os_free(ctx);\n}\n\n/**\n *@brief Clear the memory cache.\n */\nvoid ICACHE_FLASH_ATTR bi_clear_cache(BI_CTX *ctx)\n{\n    bigint *p, *pn;\n\n    if (ctx->free_list == NULL)\n        return;\n    \n    for (p = ctx->free_list; p != NULL; p = pn)\n    {\n        pn = p->next;\n        os_free(p->comps);\n        os_free(p);\n    }\n\n    ctx->free_count = 0;\n    ctx->free_list = NULL;\n}\n\n/**\n * @brief Increment the number of references to this object. \n * It does not do a full copy.\n * @param bi [in]   The bigint to copy.\n * @return A reference to the same bigint.\n */\nbigint * ICACHE_FLASH_ATTR bi_copy(bigint *bi)\n{\n    check(bi);\n    if (bi->refs != PERMANENT)\n        bi->refs++;\n    return bi;\n}\n\n/**\n * @brief Simply make a bigint object \"unfreeable\" if bi_free() is called on it.\n *\n * For this object to be freed, bi_depermanent() must be called.\n * @param bi [in]   The bigint to be made permanent.\n */\nvoid ICACHE_FLASH_ATTR bi_permanent(bigint *bi)\n{\n    check(bi);\n    if (bi->refs != 1)\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"bi_permanent: refs was not 1\\n\");\n#endif\n        return;     /* wujg : org ----> abort(); */\n    }\n\n    bi->refs = PERMANENT;\n}\n\n/**\n * @brief Take a permanent object and make it eligible for freedom.\n * @param bi [in]   The bigint to be made back to temporary.\n */\nvoid ICACHE_FLASH_ATTR bi_depermanent(bigint *bi)\n{\n    check(bi);\n    if (bi->refs != PERMANENT)\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"bi_depermanent: bigint was not permanent\\n\");\n#endif\n        return;     /* wujg : org ----> abort(); */\n    }\n\n    bi->refs = 1;\n}\n\n/**\n * @brief Free a bigint object so it can be used again. \n *\n * The memory itself it not actually freed, just tagged as being available \n * @param ctx [in]   The bigint session context.\n * @param bi [in]    The bigint to be freed.\n */\nvoid ICACHE_FLASH_ATTR bi_free(BI_CTX *ctx, bigint *bi)\n{\n    check(bi);\n    if (bi->refs == PERMANENT)\n    {\n        return;\n    }\n\n    if (--bi->refs > 0)\n    {\n        return;\n    }\n\n    bi->next = ctx->free_list;\n    ctx->free_list = bi;\n    ctx->free_count++;\n\n    if (--ctx->active_count < 0)\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"bi_free: active_count went negative \"\n                \"- double-freed bigint?\\n\");\n#endif\n        return;     /* wujg : org ----> abort(); */\n    }\n}\n\n/**\n * @brief Convert an (unsigned) integer into a bigint.\n * @param ctx [in]   The bigint session context.\n * @param i [in]     The (unsigned) integer to be converted.\n * \n */\nbigint * ICACHE_FLASH_ATTR int_to_bi(BI_CTX *ctx, comp i)\n{\n    bigint *biR = alloc(ctx, 1);\n    biR->comps[0] = i;\n    return biR;\n}\n\n/**\n * @brief Do a full copy of the bigint object.\n * @param ctx [in]   The bigint session context.\n * @param bi  [in]   The bigint object to be copied.\n */\nbigint * ICACHE_FLASH_ATTR bi_clone(BI_CTX *ctx, const bigint *bi)\n{\n    bigint *biR = alloc(ctx, bi->size);\n    check(bi);\n    os_memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);\n    return biR;\n}\n\n/**\n * @brief Perform an addition operation between two bigints.\n * @param ctx [in]  The bigint session context.\n * @param bia [in]  A bigint.\n * @param bib [in]  Another bigint.\n * @return The result of the addition.\n */\nbigint * ICACHE_FLASH_ATTR bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)\n{\n    int n;\n    comp carry = 0;\n    comp *pa, *pb;\n\n    check(bia);\n    check(bib);\n\n    n = max(bia->size, bib->size);\n    more_comps(bia, n+1);\n    more_comps(bib, n);\n    pa = bia->comps;\n    pb = bib->comps;\n\n    do\n    {\n        comp  sl, rl, cy1;\n        sl = *pa + *pb++;\n        rl = sl + carry;\n        cy1 = sl < *pa;\n        carry = cy1 | (rl < sl);\n        *pa++ = rl;\n    } while (--n != 0);\n\n    *pa = carry;                  /* do overflow */\n    bi_free(ctx, bib);\n    return trim(bia);\n}\n\n/**\n * @brief Perform a subtraction operation between two bigints.\n * @param ctx [in]  The bigint session context.\n * @param bia [in]  A bigint.\n * @param bib [in]  Another bigint.\n * @param is_negative [out] If defined, indicates that the result was negative.\n * is_negative may be null.\n * @return The result of the subtraction. The result is always positive.\n */\nbigint * ICACHE_FLASH_ATTR bi_subtract(BI_CTX *ctx, \n        bigint *bia, bigint *bib, int *is_negative)\n{\n    int n = bia->size;\n    comp *pa, *pb, carry = 0;\n\n    check(bia);\n    check(bib);\n\n    more_comps(bib, n);\n    pa = bia->comps;\n    pb = bib->comps;\n\n    do \n    {\n        comp sl, rl, cy1;\n        sl = *pa - *pb++;\n        rl = sl - carry;\n        cy1 = sl > *pa;\n        carry = cy1 | (rl > sl);\n        *pa++ = rl;\n    } while (--n != 0);\n\n    if (is_negative)    /* indicate a negative result */\n    {\n        *is_negative = carry;\n    }\n\n    bi_free(ctx, trim(bib));    /* put bib back to the way it was */\n    return trim(bia);\n}\n\n/**\n * Perform a multiply between a bigint an an (unsigned) integer\n */\nstatic bigint * ICACHE_FLASH_ATTR bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)\n{\n    int j = 0, n = bia->size;\n    bigint *biR = alloc(ctx, n + 1);\n    comp carry = 0;\n    comp *r = biR->comps;\n    comp *a = bia->comps;\n\n    check(bia);\n\n    /* clear things to start with */\n    os_memset(r, 0, ((n+1)*COMP_BYTE_SIZE));\n\n    do\n    {\n        long_comp tmp = *r + (long_comp)a[j]*b + carry;\n        *r++ = (comp)tmp;              /* downsize */\n        carry = (comp)(tmp >> COMP_BIT_SIZE);\n    } while (++j < n);\n\n    *r = carry;\n    bi_free(ctx, bia);\n    return trim(biR);\n}\n\n/**\n * @brief Does both division and modulo calculations. \n *\n * Used extensively when doing classical reduction.\n * @param ctx [in]  The bigint session context.\n * @param u [in]    A bigint which is the numerator.\n * @param v [in]    Either the denominator or the modulus depending on the mode.\n * @param is_mod [n] Determines if this is a normal division (0) or a reduction\n * (1).\n * @return  The result of the division/reduction.\n */\nbigint * ICACHE_FLASH_ATTR bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)\n{\n    int n = v->size, m = u->size-n;\n    int j = 0, orig_u_size = u->size;\n    uint8_t mod_offset = ctx->mod_offset;\n    comp d;\n    bigint *quotient, *tmp_u;\n    comp q_dash;\n\n    check(u);\n    check(v);\n\n    /* if doing reduction and we are < mod, then return mod */\n    if (is_mod && bi_compare(v, u) > 0)\n    {\n        bi_free(ctx, v);\n        return u;\n    }\n\n    quotient = alloc(ctx, m+1);\n    tmp_u = alloc(ctx, n+1);\n    v = trim(v);        /* make sure we have no leading 0's */\n    d = (comp)((long_comp)COMP_RADIX/(V1+1));\n\n    /* clear things to start with */\n    os_memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));\n\n    /* normalise */\n    if (d > 1)\n    {\n        u = bi_int_multiply(ctx, u, d);\n\n        if (is_mod)\n        {\n            v = ctx->bi_normalised_mod[mod_offset];\n        }\n        else\n        {\n            v = bi_int_multiply(ctx, v, d);\n        }\n    }\n\n    if (orig_u_size == u->size)  /* new digit position u0 */\n    {\n        more_comps(u, orig_u_size + 1);\n    }\n\n    do\n    {\n        /* get a temporary short version of u */\n        os_memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);\n\n        /* calculate q' */\n        if (U(0) == V1)\n        {\n            q_dash = COMP_RADIX-1;\n        }\n        else\n        {\n            q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);\n\n            if (v->size > 1 && V2)\n            {\n                /* we are implementing the following:\n                if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - \n                        q_dash*V1)*COMP_RADIX) + U(2))) ... */\n                comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - \n                                            (long_comp)q_dash*V1);\n                if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))\n                {\n                    q_dash--;\n                }\n            }\n        }\n\n        /* multiply and subtract */\n        if (q_dash)\n        {\n            int is_negative;\n            tmp_u = bi_subtract(ctx, tmp_u, \n                    bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);\n            more_comps(tmp_u, n+1);\n\n            Q(j) = q_dash; \n\n            /* add back */\n            if (is_negative)\n            {\n                Q(j)--;\n                tmp_u = bi_add(ctx, tmp_u, bi_copy(v));\n\n                /* lop off the carry */\n                tmp_u->size--;\n                v->size--;\n            }\n        }\n        else\n        {\n            Q(j) = 0; \n        }\n\n        /* copy back to u */\n        os_memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);\n    } while (++j <= m);\n\n    bi_free(ctx, tmp_u);\n    bi_free(ctx, v);\n\n    if (is_mod)     /* get the remainder */\n    {\n        bi_free(ctx, quotient);\n        return bi_int_divide(ctx, trim(u), d);\n    }\n    else            /* get the quotient */\n    {\n        bi_free(ctx, u);\n        return trim(quotient);\n    }\n}\n\n/*\n * Perform an integer divide on a bigint.\n */\nstatic bigint * ICACHE_FLASH_ATTR bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom)\n{\n    int i = biR->size - 1;\n    long_comp r = 0;\n\n    check(biR);\n\n    do\n    {\n        r = (r<<COMP_BIT_SIZE) + biR->comps[i];\n        biR->comps[i] = (comp)(r / denom);\n        r %= denom;\n    } while (--i >= 0);\n\n    return trim(biR);\n}\n\n#ifdef CONFIG_BIGINT_MONTGOMERY\n/**\n * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, \n * where B^-1(B-1) mod N=1. Actually, only the least significant part of \n * N' is needed, hence the definition N0'=N' mod b. We reproduce below the \n * simple algorithm from an article by Dusse and Kaliski to efficiently \n * find N0' from N0 and b */\nstatic comp ICACHE_FLASH_ATTR modular_inverse(bigint *bim)\n{\n    int i;\n    comp t = 1;\n    comp two_2_i_minus_1 = 2;   /* 2^(i-1) */\n    long_comp two_2_i = 4;      /* 2^i */\n    comp N = bim->comps[0];\n\n    for (i = 2; i <= COMP_BIT_SIZE; i++)\n    {\n        if ((long_comp)N*t%two_2_i >= two_2_i_minus_1)\n        {\n            t += two_2_i_minus_1;\n        }\n\n        two_2_i_minus_1 <<= 1;\n        two_2_i <<= 1;\n    }\n\n    return (comp)(COMP_RADIX-t);\n}\n#endif\n\n#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \\\n    defined(CONFIG_BIGINT_MONTGOMERY)\n/**\n * Take each component and shift down (in terms of components) \n */\nstatic bigint * ICACHE_FLASH_ATTR comp_right_shift(bigint *biR, int num_shifts)\n{\n    int i = biR->size-num_shifts;\n    comp *x = biR->comps;\n    comp *y = &biR->comps[num_shifts];\n\n    check(biR);\n\n    if (i <= 0)     /* have we completely right shifted? */\n    {\n        biR->comps[0] = 0;  /* return 0 */\n        biR->size = 1;\n        return biR;\n    }\n\n    do\n    {\n        *x++ = *y++;\n    } while (--i > 0);\n\n    biR->size -= num_shifts;\n    return biR;\n}\n\n/**\n * Take each component and shift it up (in terms of components) \n */\nstatic bigint * ICACHE_FLASH_ATTR comp_left_shift(bigint *biR, int num_shifts)\n{\n    int i = biR->size-1;\n    comp *x, *y;\n\n    check(biR);\n\n    if (num_shifts <= 0)\n    {\n        return biR;\n    }\n\n    more_comps(biR, biR->size + num_shifts);\n\n    x = &biR->comps[i+num_shifts];\n    y = &biR->comps[i];\n\n    do\n    {\n        *x-- = *y--;\n    } while (i--);\n\n    os_memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */\n    return biR;\n}\n#endif\n\n/**\n * @brief Allow a binary sequence to be imported as a bigint.\n * @param ctx [in]  The bigint session context.\n * @param data [in] The data to be converted.\n * @param size [in] The number of bytes of data.\n * @return A bigint representing this data.\n */\nbigint * ICACHE_FLASH_ATTR bi_import(BI_CTX *ctx, const uint8_t *data, int size)\n{\n    bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);\n    int i, j = 0, offset = 0;\n\n    os_memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);\n\n    for (i = size-1; i >= 0; i--)\n    {\n        biR->comps[offset] += data[i] << (j*8);\n\n        if (++j == COMP_BYTE_SIZE)\n        {\n            j = 0;\n            offset ++;\n        }\n    }\n\n    return trim(biR);\n}\n\n#ifdef CONFIG_SSL_FULL_MODE\n/**\n * @brief The testharness uses this code to import text hex-streams and \n * convert them into bigints.\n * @param ctx [in]  The bigint session context.\n * @param data [in] A string consisting of hex characters. The characters must\n * be in upper case.\n * @return A bigint representing this data.\n */\nbigint * ICACHE_FLASH_ATTR bi_str_import(BI_CTX *ctx, const char *data)\n{\n    int size = os_strlen(data);\n    bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES);\n    int i, j = 0, offset = 0;\n    os_memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);\n\n    for (i = size-1; i >= 0; i--)\n    {\n        int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10);\n        biR->comps[offset] += num << (j*4);\n\n        if (++j == COMP_NUM_NIBBLES)\n        {\n            j = 0;\n            offset ++;\n        }\n    }\n\n    return biR;\n}\n\nvoid ICACHE_FLASH_ATTR bi_print(const char *label, bigint *x)\n{\n    int i, j;\n\n    if (x == NULL)\n    {\n        ssl_printf(\"%s: (null)\\n\", label);\n        return;\n    }\n\n    ssl_printf(\"%s: (size %d)\\n\", label, x->size);\n    for (i = x->size-1; i >= 0; i--)\n    {\n        for (j = COMP_NUM_NIBBLES-1; j >= 0; j--)\n        {\n            comp mask = 0x0f << (j*4);\n            comp num = (x->comps[i] & mask) >> (j*4);\n            os_putc((num <= 9) ? (num + '0') : (num + 'A' - 10));\n        }\n    }  \n\n    ssl_printf(\"\\n\");\n}\n#endif\n\n/**\n * @brief Take a bigint and convert it into a byte sequence. \n *\n * This is useful after a decrypt operation.\n * @param ctx [in]  The bigint session context.\n * @param x [in]  The bigint to be converted.\n * @param data [out] The converted data as a byte stream.\n * @param size [in] The maximum size of the byte stream. Unused bytes will be\n * zeroed.\n */\nvoid ICACHE_FLASH_ATTR bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)\n{\n    int i, j, k = size-1;\n\n    check(x);\n    os_memset(data, 0, size);  /* ensure all leading 0's are cleared */\n\n    for (i = 0; i < x->size; i++)\n    {\n        for (j = 0; j < COMP_BYTE_SIZE; j++)\n        {\n            comp mask = 0xff << (j*8);\n            int num = (x->comps[i] & mask) >> (j*8);\n            data[k--] = num;\n\n            if (k < 0)\n            {\n                goto buf_done;\n            }\n        }\n    }\nbuf_done:\n\n    bi_free(ctx, x);\n}\n\n/**\n * @brief Pre-calculate some of the expensive steps in reduction. \n *\n * This function should only be called once (normally when a session starts).\n * When the session is over, bi_free_mod() should be called. bi_mod_power()\n * relies on this function being called.\n * @param ctx [in]  The bigint session context.\n * @param bim [in]  The bigint modulus that will be used.\n * @param mod_offset [in] There are three moduluii that can be stored - the\n * standard modulus, and its two primes p and q. This offset refers to which\n * modulus we are referring to.\n * @see bi_free_mod(), bi_mod_power().\n */\nvoid ICACHE_FLASH_ATTR bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)\n{\n    int k = bim->size;\n    comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));\n#ifdef CONFIG_BIGINT_MONTGOMERY\n    bigint *R, *R2;\n#endif\n\n    ctx->bi_mod[mod_offset] = bim;\n    bi_permanent(ctx->bi_mod[mod_offset]);\n    ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);\n    bi_permanent(ctx->bi_normalised_mod[mod_offset]);\n\n#if defined(CONFIG_BIGINT_MONTGOMERY)\n    /* set montgomery variables */\n    R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1);     /* R */\n    R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1);  /* R^2 */\n    ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2);             /* R^2 mod m */\n    ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R);               /* R mod m */\n\n    bi_permanent(ctx->bi_RR_mod_m[mod_offset]);\n    bi_permanent(ctx->bi_R_mod_m[mod_offset]);\n\n    ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]);\n\n#elif defined (CONFIG_BIGINT_BARRETT)\n    ctx->bi_mu[mod_offset] = \n        bi_divide(ctx, comp_left_shift(\n            bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0);\n    bi_permanent(ctx->bi_mu[mod_offset]);\n#endif\n}\n\n/**\n * @brief Used when cleaning various bigints at the end of a session.\n * @param ctx [in]  The bigint session context.\n * @param mod_offset [in] The offset to use.\n * @see bi_set_mod().\n */\nvoid ICACHE_FLASH_ATTR bi_free_mod(BI_CTX *ctx, int mod_offset)\n{\n    bi_depermanent(ctx->bi_mod[mod_offset]);\n    bi_free(ctx, ctx->bi_mod[mod_offset]);\n#if defined (CONFIG_BIGINT_MONTGOMERY)\n    bi_depermanent(ctx->bi_RR_mod_m[mod_offset]);\n    bi_depermanent(ctx->bi_R_mod_m[mod_offset]);\n    bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]);\n    bi_free(ctx, ctx->bi_R_mod_m[mod_offset]);\n#elif defined(CONFIG_BIGINT_BARRETT)\n    bi_depermanent(ctx->bi_mu[mod_offset]); \n    bi_free(ctx, ctx->bi_mu[mod_offset]);\n#endif\n    bi_depermanent(ctx->bi_normalised_mod[mod_offset]); \n    bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);\n}\n\n/** \n * Perform a standard multiplication between two bigints.\n *\n * Barrett reduction has no need for some parts of the product, so ignore bits\n * of the multiply. This routine gives Barrett its big performance\n * improvements over Classical/Montgomery reduction methods. \n */\nstatic bigint * ICACHE_FLASH_ATTR regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, \n        int inner_partial, int outer_partial)\n{\n    int i = 0, j;\n    int n = bia->size;\n    int t = bib->size;\n    bigint *biR = alloc(ctx, n + t);\n    comp *sr = biR->comps;\n    comp *sa = bia->comps;\n    comp *sb = bib->comps;\n\n    check(bia);\n    check(bib);\n\n    /* clear things to start with */\n    os_memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));\n\n    do \n    {\n        long_comp tmp;\n        comp carry = 0;\n        int r_index = i;\n        j = 0;\n\n        if (outer_partial && outer_partial-i > 0 && outer_partial < n)\n        {\n            r_index = outer_partial-1;\n            j = outer_partial-i-1;\n        }\n\n        do\n        {\n            if (inner_partial && r_index >= inner_partial) \n            {\n                break;\n            }\n\n            tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry;\n            sr[r_index++] = (comp)tmp;              /* downsize */\n            carry = tmp >> COMP_BIT_SIZE;\n        } while (++j < n);\n\n        sr[r_index] = carry;\n    } while (++i < t);\n\n    bi_free(ctx, bia);\n    bi_free(ctx, bib);\n    return trim(biR);\n}\n\n#ifdef CONFIG_BIGINT_KARATSUBA\n/*\n * Karatsuba improves on regular multiplication due to only 3 multiplications \n * being done instead of 4. The additional additions/subtractions are O(N) \n * rather than O(N^2) and so for big numbers it saves on a few operations \n */\nstatic bigint * ICACHE_FLASH_ATTR karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square)\n{\n    bigint *x0, *x1;\n    bigint *p0, *p1, *p2;\n    int m;\n\n    if (is_square)\n    {\n        m = (bia->size + 1)/2;\n    }\n    else\n    {\n        m = (max(bia->size, bib->size) + 1)/2;\n    }\n\n    x0 = bi_clone(ctx, bia);\n    x0->size = m;\n    x1 = bi_clone(ctx, bia);\n    comp_right_shift(x1, m);\n    bi_free(ctx, bia);\n\n    /* work out the 3 partial products */\n    if (is_square)\n    {\n        p0 = bi_square(ctx, bi_copy(x0));\n        p2 = bi_square(ctx, bi_copy(x1));\n        p1 = bi_square(ctx, bi_add(ctx, x0, x1));\n    }\n    else /* normal multiply */\n    {\n        bigint *y0, *y1;\n        y0 = bi_clone(ctx, bib);\n        y0->size = m;\n        y1 = bi_clone(ctx, bib);\n        comp_right_shift(y1, m);\n        bi_free(ctx, bib);\n\n        p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0));\n        p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1));\n        p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1));\n    }\n\n    p1 = bi_subtract(ctx, \n            bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL);\n\n    comp_left_shift(p1, m);\n    comp_left_shift(p2, 2*m);\n    return bi_add(ctx, p1, bi_add(ctx, p0, p2));\n}\n#endif\n\n/**\n * @brief Perform a multiplication operation between two bigints.\n * @param ctx [in]  The bigint session context.\n * @param bia [in]  A bigint.\n * @param bib [in]  Another bigint.\n * @return The result of the multiplication.\n */\nbigint * ICACHE_FLASH_ATTR bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)\n{\n    check(bia);\n    check(bib);\n\n#ifdef CONFIG_BIGINT_KARATSUBA\n    if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH)\n    {\n        return regular_multiply(ctx, bia, bib, 0, 0);\n    }\n\n    return karatsuba(ctx, bia, bib, 0);\n#else\n    return regular_multiply(ctx, bia, bib, 0, 0);\n#endif\n}\n\n#ifdef CONFIG_BIGINT_SQUARE\n/*\n * Perform the actual square operion. It takes into account overflow.\n */\nstatic bigint * ICACHE_FLASH_ATTR regular_square(BI_CTX *ctx, bigint *bi)\n{\n    int t = bi->size;\n    int i = 0, j;\n    bigint *biR = alloc(ctx, t*2+1);\n    comp *w = biR->comps;\n    comp *x = bi->comps;\n    long_comp carry;\n    os_memset(w, 0, biR->size*COMP_BYTE_SIZE);\n\n    do\n    {\n        long_comp tmp = w[2*i] + (long_comp)x[i]*x[i];\n        w[2*i] = (comp)tmp;\n        carry = tmp >> COMP_BIT_SIZE;\n\n        for (j = i+1; j < t; j++)\n        {\n            uint8_t c = 0;\n            long_comp xx = (long_comp)x[i]*x[j];\n            if ((COMP_MAX-xx) < xx)\n                c = 1;\n\n            tmp = (xx<<1);\n\n            if ((COMP_MAX-tmp) < w[i+j])\n                c = 1;\n\n            tmp += w[i+j];\n\n            if ((COMP_MAX-tmp) < carry)\n                c = 1;\n\n            tmp += carry;\n            w[i+j] = (comp)tmp;\n            carry = tmp >> COMP_BIT_SIZE;\n\n            if (c)\n                carry += COMP_RADIX;\n        }\n\n        tmp = w[i+t] + carry;\n        w[i+t] = (comp)tmp;\n        w[i+t+1] = tmp >> COMP_BIT_SIZE;\n    } while (++i < t);\n\n    bi_free(ctx, bi);\n    return trim(biR);\n}\n\n/**\n * @brief Perform a square operation on a bigint.\n * @param ctx [in]  The bigint session context.\n * @param bia [in]  A bigint.\n * @return The result of the multiplication.\n */\nbigint * ICACHE_FLASH_ATTR bi_square(BI_CTX *ctx, bigint *bia)\n{\n    check(bia);\n\n#ifdef CONFIG_BIGINT_KARATSUBA\n    if (bia->size < SQU_KARATSUBA_THRESH) \n    {\n        return regular_square(ctx, bia);\n    }\n\n    return karatsuba(ctx, bia, NULL, 1);\n#else\n    return regular_square(ctx, bia);\n#endif\n}\n#endif\n\n/**\n * @brief Compare two bigints.\n * @param bia [in]  A bigint.\n * @param bib [in]  Another bigint.\n * @return -1 if smaller, 1 if larger and 0 if equal.\n */\nint ICACHE_FLASH_ATTR bi_compare(bigint *bia, bigint *bib)\n{\n    int r, i;\n\n    check(bia);\n    check(bib);\n\n    if (bia->size > bib->size)\n        r = 1;\n    else if (bia->size < bib->size)\n        r = -1;\n    else\n    {\n        comp *a = bia->comps; \n        comp *b = bib->comps; \n\n        /* Same number of components.  Compare starting from the high end\n         * and working down. */\n        r = 0;\n        i = bia->size - 1;\n\n        do \n        {\n            if (a[i] > b[i])\n            { \n                r = 1;\n                break; \n            }\n            else if (a[i] < b[i])\n            { \n                r = -1;\n                break; \n            }\n        } while (--i >= 0);\n    }\n\n    return r;\n}\n\n/*\n * Allocate and zero more components.  Does not consume bi. \n */\nstatic void ICACHE_FLASH_ATTR more_comps(bigint *bi, int n)\n{\n    if (n > bi->max_comps)\n    {\n        bi->max_comps = max(bi->max_comps * 2, n);\n        bi->comps = (comp*)os_realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);\n    }\n\n    if (n > bi->size)\n    {\n        os_memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);\n    }\n\n    bi->size = n;\n}\n\n/*\n * Make a new empty bigint. It may just use an old one if one is available.\n * Otherwise get one off the heap.\n */\nstatic bigint * ICACHE_FLASH_ATTR alloc(BI_CTX *ctx, int size)\n{\n    bigint *biR;\n\n    /* Can we recycle an old bigint? */\n    if (ctx->free_list != NULL)\n    {\n        biR = ctx->free_list;\n        ctx->free_list = biR->next;\n        ctx->free_count--;\n\n        if (biR->refs != 0)\n        {\n#ifdef CONFIG_SSL_FULL_MODE\n            ssl_printf(\"alloc: refs was not 0\\n\");\n#endif\n            return;     /* wujg : org ----> abort(); */\n        }\n\n        more_comps(biR, size);\n    }\n    else\n    {\n        /* No free bigints available - create a new one. */\n        biR = (bigint *)os_malloc(sizeof(bigint));\n        biR->comps = (comp*)os_malloc(size * COMP_BYTE_SIZE);\n        biR->max_comps = size;  /* give some space to spare */\n    }\n\n    biR->size = size;\n    biR->refs = 1;\n    biR->next = NULL;\n    ctx->active_count++;\n    return biR;\n}\n\n/*\n * Work out the highest '1' bit in an exponent. Used when doing sliding-window\n * exponentiation.\n */\nstatic int ICACHE_FLASH_ATTR find_max_exp_index(bigint *biexp)\n{\n    int i = COMP_BIT_SIZE-1;\n    comp shift = COMP_RADIX/2;\n    comp test = biexp->comps[biexp->size-1];    /* assume no leading zeroes */\n\n    check(biexp);\n\n    do\n    {\n        if (test & shift)\n        {\n            return i+(biexp->size-1)*COMP_BIT_SIZE;\n        }\n\n        shift >>= 1;\n    } while (i-- != 0);\n\n    return -1;      /* error - must have been a leading 0 */\n}\n\n/*\n * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window\n * exponentiation.\n */\nstatic int ICACHE_FLASH_ATTR exp_bit_is_one(bigint *biexp, int offset)\n{\n    comp test = biexp->comps[offset / COMP_BIT_SIZE];\n    int num_shifts = offset % COMP_BIT_SIZE;\n    comp shift = 1;\n    int i;\n\n    check(biexp);\n\n    for (i = 0; i < num_shifts; i++)\n    {\n        shift <<= 1;\n    }\n\n    return (test & shift) != 0;\n}\n\n#ifdef CONFIG_BIGINT_CHECK_ON\n/*\n * Perform a sanity check on bi.\n */\nstatic void ICACHE_FLASH_ATTR check(const bigint *bi)\n{\n    if (bi->refs <= 0)\n    {\n        ssl_printf(\"check: zero or negative refs in bigint\\n\");\n        return;     /* wujg : org ----> abort(); */\n    }\n\n    if (bi->next != NULL)\n    {\n        ssl_printf(\"check: attempt to use a bigint from \"\n                \"the free list\\n\");\n        return;     /* wujg : org ----> abort(); */\n    }\n}\n#endif\n\n/*\n * Delete any leading 0's (and allow for 0).\n */\nstatic bigint * ICACHE_FLASH_ATTR trim(bigint *bi)\n{\n    check(bi);\n\n    while (bi->comps[bi->size-1] == 0 && bi->size > 1)\n    {\n        bi->size--;\n    }\n\n    return bi;\n}\n\n#if defined(CONFIG_BIGINT_MONTGOMERY)\n/**\n * @brief Perform a single montgomery reduction.\n * @param ctx [in]  The bigint session context.\n * @param bixy [in]  A bigint.\n * @return The result of the montgomery reduction.\n */\nbigint * ICACHE_FLASH_ATTR bi_mont(BI_CTX *ctx, bigint *bixy)\n{\n    int i = 0, n;\n    uint8_t mod_offset = ctx->mod_offset;\n    bigint *bim = ctx->bi_mod[mod_offset];\n    comp mod_inv = ctx->N0_dash[mod_offset];\n\n    check(bixy);\n\n    if (ctx->use_classical)     /* just use classical instead */\n    {\n        return bi_mod(ctx, bixy);\n    }\n\n    n = bim->size;\n\n    do\n    {\n        bixy = bi_add(ctx, bixy, comp_left_shift(\n                    bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i));\n    } while (++i < n);\n\n    comp_right_shift(bixy, n);\n\n    if (bi_compare(bixy, bim) >= 0)\n    {\n        bixy = bi_subtract(ctx, bixy, bim, NULL);\n    }\n\n    return bixy;\n}\n\n#elif defined(CONFIG_BIGINT_BARRETT)\n/*\n * Stomp on the most significant components to give the illusion of a \"mod base\n * radix\" operation \n */\nstatic bigint * ICACHE_FLASH_ATTR comp_mod(bigint *bi, int mod)\n{\n    check(bi);\n\n    if (bi->size > mod)\n    {\n        bi->size = mod;\n    }\n\n    return bi;\n}\n\n/**\n * @brief Perform a single Barrett reduction.\n * @param ctx [in]  The bigint session context.\n * @param bi [in]  A bigint.\n * @return The result of the Barrett reduction.\n */\nbigint * ICACHE_FLASH_ATTR bi_barrett(BI_CTX *ctx, bigint *bi)\n{\n    bigint *q1, *q2, *q3, *r1, *r2, *r;\n    uint8_t mod_offset = ctx->mod_offset;\n    bigint *bim = ctx->bi_mod[mod_offset];\n    int k = bim->size;\n\n    check(bi);\n    check(bim);\n\n    /* use Classical method instead  - Barrett cannot help here */\n    if (bi->size > k*2)\n    {\n        return bi_mod(ctx, bi);\n    }\n\n    q1 = comp_right_shift(bi_clone(ctx, bi), k-1);\n\n    /* do outer partial multiply */\n    q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); \n    q3 = comp_right_shift(q2, k+1);\n    r1 = comp_mod(bi, k+1);\n\n    /* do inner partial multiply */\n    r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1);\n    r = bi_subtract(ctx, r1, r2, NULL);\n\n    /* if (r >= m) r = r - m; */\n    if (bi_compare(r, bim) >= 0)\n    {\n        r = bi_subtract(ctx, r, bim, NULL);\n    }\n\n    return r;\n}\n#endif /* CONFIG_BIGINT_BARRETT */\n\n#ifdef CONFIG_BIGINT_SLIDING_WINDOW\n/*\n * Work out g1, g3, g5, g7... etc for the sliding-window algorithm \n */\nstatic void ICACHE_FLASH_ATTR precompute_slide_window(BI_CTX *ctx, int window, bigint *g1)\n{\n    int k = 1, i;\n    bigint *g2;\n\n    for (i = 0; i < window-1; i++)   /* compute 2^(window-1) */\n    {\n        k <<= 1;\n    }\n\n    ctx->g = (bigint **)os_malloc(k*sizeof(bigint *));\n    ctx->g[0] = bi_clone(ctx, g1);\n    bi_permanent(ctx->g[0]);\n    g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0]));   /* g^2 */\n\n    for (i = 1; i < k; i++)\n    {\n        ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2)));\n        bi_permanent(ctx->g[i]);\n    }\n\n    bi_free(ctx, g2);\n    ctx->window = k;\n}\n#endif\n\n/**\n * @brief Perform a modular exponentiation.\n *\n * This function requires bi_set_mod() to have been called previously. This is \n * one of the optimisations used for performance.\n * @param ctx [in]  The bigint session context.\n * @param bi  [in]  The bigint on which to perform the mod power operation.\n * @param biexp [in] The bigint exponent.\n * @return The result of the mod exponentiation operation\n * @see bi_set_mod().\n */\nbigint * ICACHE_FLASH_ATTR bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)\n{\n    int i = find_max_exp_index(biexp), j, window_size = 1;\n    bigint *biR = int_to_bi(ctx, 1);\n\n#if defined(CONFIG_BIGINT_MONTGOMERY)\n    uint8_t mod_offset = ctx->mod_offset;\n    if (!ctx->use_classical)\n    {\n        /* preconvert */\n        bi = bi_mont(ctx, \n                bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset]));    /* x' */\n        bi_free(ctx, biR);\n        biR = ctx->bi_R_mod_m[mod_offset];                              /* A */\n    }\n#endif\n\n    check(bi);\n    check(biexp);\n\n#ifdef CONFIG_BIGINT_SLIDING_WINDOW\n    for (j = i; j > 32; j /= 5) /* work out an optimum size */\n        window_size++;\n\n    /* work out the slide constants */\n    precompute_slide_window(ctx, window_size, bi);\n#else   /* just one constant */\n    ctx->g = (bigint **)os_malloc(sizeof(bigint *));\n    ctx->g[0] = bi_clone(ctx, bi);\n    ctx->window = 1;\n    bi_permanent(ctx->g[0]);\n#endif\n\n    /* if sliding-window is off, then only one bit will be done at a time and\n     * will reduce to standard left-to-right exponentiation */\n    do\n    {\n        if (exp_bit_is_one(biexp, i))\n        {\n            int l = i-window_size+1;\n            int part_exp = 0;\n\n            if (l < 0)  /* LSB of exponent will always be 1 */\n                l = 0;\n            else\n            {\n                while (exp_bit_is_one(biexp, l) == 0)\n                    l++;    /* go back up */\n            }\n\n            /* build up the section of the exponent */\n            for (j = i; j >= l; j--)\n            {\n                biR = bi_residue(ctx, bi_square(ctx, biR));\n                if (exp_bit_is_one(biexp, j))\n                    part_exp++;\n\n                if (j != l)\n                    part_exp <<= 1;\n            }\n\n            part_exp = (part_exp-1)/2;  /* adjust for array */\n            biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp]));\n            i = l-1;\n        }\n        else    /* square it */\n        {\n            biR = bi_residue(ctx, bi_square(ctx, biR));\n            i--;\n        }\n    } while (i >= 0);\n     \n    /* cleanup */\n    for (i = 0; i < ctx->window; i++)\n    {\n        bi_depermanent(ctx->g[i]);\n        bi_free(ctx, ctx->g[i]);\n    }\n\n    os_free(ctx->g);\n    bi_free(ctx, bi);\n    bi_free(ctx, biexp);\n#if defined CONFIG_BIGINT_MONTGOMERY\n    return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */\n#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */\n    return biR;\n#endif\n}\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n/**\n * @brief Perform a modular exponentiation using a temporary modulus.\n *\n * We need this function to check the signatures of certificates. The modulus\n * of this function is temporary as it's just used for authentication.\n * @param ctx [in]  The bigint session context.\n * @param bi  [in]  The bigint to perform the exp/mod.\n * @param bim [in]  The temporary modulus.\n * @param biexp [in] The bigint exponent.\n * @return The result of the mod exponentiation operation\n * @see bi_set_mod().\n */\nbigint * ICACHE_FLASH_ATTR bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp)\n{\n    bigint *biR, *tmp_biR;\n\n    /* Set up a temporary bigint context and transfer what we need between\n     * them. We need to do this since we want to keep the original modulus\n     * which is already in this context. This operation is only called when\n     * doing peer verification, and so is not expensive :-) */\n    BI_CTX *tmp_ctx = bi_initialize();\n    bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET);\n    tmp_biR = bi_mod_power(tmp_ctx, \n                bi_clone(tmp_ctx, bi), \n                bi_clone(tmp_ctx, biexp));\n    biR = bi_clone(ctx, tmp_biR);\n    bi_free(tmp_ctx, tmp_biR);\n    bi_free_mod(tmp_ctx, BIGINT_M_OFFSET);\n    bi_terminate(tmp_ctx);\n\n    bi_free(ctx, bi);\n    bi_free(ctx, bim);\n    bi_free(ctx, biexp);\n    return biR;\n}\n#endif\n\n#ifdef CONFIG_BIGINT_CRT\n/**\n * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts.\n *\n * @param ctx [in]  The bigint session context.\n * @param bi  [in]  The bigint to perform the exp/mod.\n * @param dP [in] CRT's dP bigint\n * @param dQ [in] CRT's dQ bigint\n * @param p [in] CRT's p bigint\n * @param q [in] CRT's q bigint\n * @param qInv [in] CRT's qInv bigint\n * @return The result of the CRT operation\n */\nbigint * ICACHE_FLASH_ATTR bi_crt(BI_CTX *ctx, bigint *bi,\n        bigint *dP, bigint *dQ,\n        bigint *p, bigint *q, bigint *qInv)\n{\n    bigint *m1, *m2, *h;\n\n    /* Montgomery has a condition the 0 < x, y < m and these products violate\n     * that condition. So disable Montgomery when using CRT */\n#if defined(CONFIG_BIGINT_MONTGOMERY)\n    ctx->use_classical = 1;\n#endif\n    ctx->mod_offset = BIGINT_P_OFFSET;\n    m1 = bi_mod_power(ctx, bi_copy(bi), dP);\n\n    ctx->mod_offset = BIGINT_Q_OFFSET;\n    m2 = bi_mod_power(ctx, bi, dQ);\n\n    h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL);\n    h = bi_multiply(ctx, h, qInv);\n    ctx->mod_offset = BIGINT_P_OFFSET;\n    h = bi_residue(ctx, h);\n#if defined(CONFIG_BIGINT_MONTGOMERY)\n    ctx->use_classical = 0;         /* reset for any further operation */\n#endif\n    return bi_add(ctx, m2, bi_multiply(ctx, q, h));\n}\n#endif\n/** @} */\n"
  },
  {
    "path": "app/ssl/crypto/ssl_crypto_misc.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * Some misc. routines to help things out\n */\n\n#include <stdlib.h>\n//#include <string.h>\n//#include <stdarg.h>\n//#include <stdio.h>\n\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto_misc.h\"\n#ifdef CONFIG_WIN32_USE_CRYPTO_LIB\n#include \"wincrypt.h\"\n#endif\n\n#ifndef WIN32\nstatic int rng_fd = -1;\n#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)\nstatic HCRYPTPROV gCryptProv;\n#endif\n\n#if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))\n/* change to processor registers as appropriate */\n#define ENTROPY_POOL_SIZE 32\n#define ENTROPY_COUNTER1 ((((uint64_t)tv.tv_sec)<<32) | tv.tv_usec)\n#define ENTROPY_COUNTER2 rand()\nstatic uint8_t entropy_pool[ENTROPY_POOL_SIZE];\n#endif\n\nconst char * const unsupported_str = \"Error: Feature not supported\\n\";\n\n#ifndef CONFIG_SSL_SKELETON_MODE\n/** \n * Retrieve a file and put it into memory\n * @return The size of the file, or -1 on failure.\n */\nint get_file(const char *filename, uint8_t **buf)\n{\n#if 0\n    int total_bytes = 0;\n    int bytes_read = 0; \n    int filesize;\n    FILE *stream = fopen(filename, \"rb\");\n\n    if (stream == NULL)\n    {\n#ifdef CONFIG_SSL_FULL_MODE         \n        printf(\"file '%s' does not exist\\n\", filename); //TTY_FLUSH();\n#endif\n        return -1;\n    }\n\n    /* Win CE doesn't support stat() */\n    fseek(stream, 0, SEEK_END);\n    filesize = ftell(stream);\n    *buf = (uint8_t *)os_malloc(filesize);\n    fseek(stream, 0, SEEK_SET);\n\n    do\n    {\n        bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);\n        total_bytes += bytes_read;\n    } while (total_bytes < filesize && bytes_read > 0);\n    \n    fclose(stream);\n    return filesize;\n#endif\n\n    return 0;\n}\n#endif\n\n/**\n * Initialise the Random Number Generator engine.\n * - On Win32 use the platform SDK's crypto engine.\n * - On Linux use /dev/urandom\n * - If none of these work then use a custom RNG.\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_initialize()\n{\n#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)\n    rng_fd = ax_open(\"/dev/urandom\", O_RDONLY);\n#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)\n    if (!CryptAcquireContext(&gCryptProv, \n                      NULL, NULL, PROV_RSA_FULL, 0))\n    {\n        if (GetLastError() == NTE_BAD_KEYSET &&\n                !CryptAcquireContext(&gCryptProv, \n                       NULL, \n                       NULL, \n                       PROV_RSA_FULL, \n                       CRYPT_NEWKEYSET))\n        {\n            printf(\"CryptoLib: %x\\n\", unsupported_str, GetLastError());\n            exit(1);\n        }\n    }\n#else\n    /* start of with a stack to copy across */\n    int i;\n    os_memcpy(entropy_pool, &i, ENTROPY_POOL_SIZE);\n    srand((unsigned int)&i); \n#endif\n}\n\n/**\n * If no /dev/urandom, then initialise the RNG with something interesting.\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_custom_init(const uint8_t *seed_buf, int size)\n{\n#if defined(WIN32) || defined(CONFIG_WIN32_USE_CRYPTO_LIB)\n    int i;\n\n    for (i = 0; i < ENTROPY_POOL_SIZE && i < size; i++)\n        entropy_pool[i] ^= seed_buf[i];\n#endif\n}\n\n/**\n * Terminate the RNG engine.\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR RNG_terminate(void)\n{\n#ifndef WIN32\n//    close(rng_fd);\n#elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)\n    CryptReleaseContext(gCryptProv, 0);\n#endif\n}\n\n/**\n * Set a series of bytes with a random number. Individual bytes can be 0\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR get_random(int num_rand_bytes, uint8_t *rand_data)\n{   \n#if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)\n    /* use the Linux default */\n    read(rng_fd, rand_data, num_rand_bytes);    /* read from /dev/urandom */\n#elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)\n    /* use Microsoft Crypto Libraries */\n    CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);\n#else   /* nothing else to use, so use a custom RNG */\n    /* The method we use when we've got nothing better. Use RC4, time \n       and a couple of random seeds to generate a random sequence */\n    RC4_CTX rng_ctx;\n    struct timeval tv;\n    MD5_CTX rng_digest_ctx;\n    uint8_t digest[MD5_SIZE];\n    uint64_t *ep;\n    int i;\n\n    /* A proper implementation would use counters etc for entropy */\n//    gettimeofday(&tv, NULL);    \n    ep = (uint64_t *)entropy_pool;\n    ep[0] ^= ENTROPY_COUNTER1;\n    ep[1] ^= ENTROPY_COUNTER2; \n\n    /* use a digested version of the entropy pool as a key */\n    MD5_Init(&rng_digest_ctx);\n    MD5_Update(&rng_digest_ctx, entropy_pool, ENTROPY_POOL_SIZE);\n    MD5_Final(digest, &rng_digest_ctx);\n\n    /* come up with the random sequence */\n    RC4_setup(&rng_ctx, digest, MD5_SIZE); /* use as a key */\n    os_memcpy(rand_data, entropy_pool, num_rand_bytes < ENTROPY_POOL_SIZE ?\n\t\t\t\tnum_rand_bytes : ENTROPY_POOL_SIZE);\n    RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);\n\n    /* move things along */\n    for (i = ENTROPY_POOL_SIZE-1; i >= MD5_SIZE ; i--)\n        entropy_pool[i] = entropy_pool[i-MD5_SIZE];\n\n    /* insert the digest at the start of the entropy pool */\n    os_memcpy(entropy_pool, digest, MD5_SIZE);\n#endif\n}\n\n/**\n * Set a series of bytes with a random number. Individual bytes are not zero.\n */\nvoid ICACHE_FLASH_ATTR get_random_NZ(int num_rand_bytes, uint8_t *rand_data)\n{\n    int i;\n    get_random(num_rand_bytes, rand_data);\n\n    for (i = 0; i < num_rand_bytes; i++)\n    {\n        while (rand_data[i] == 0)  /* can't be 0 */\n            rand_data[i] = (uint8_t)(rand());\n    }\n}\n\n/**\n * Some useful diagnostic routines\n */\n#if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)\nint hex_finish;\nint hex_index;\n\nstatic void ICACHE_FLASH_ATTR print_hex_init(int finish)\n{\n    hex_finish = finish;\n    hex_index = 0;\n}\n\nstatic void ICACHE_FLASH_ATTR print_hex(uint8_t hex)\n{\n    static int column;\n\n    if (hex_index == 0)\n    {\n        column = 0;\n    }\n\n    ssl_printf(\"%02x \", hex);\n    if (++column == 8)\n    {\n        ssl_printf(\": \");\n    }\n    else if (column >= 16)\n    {\n        ssl_printf(\"\\n\");\n        column = 0;\n    }\n\n    if (++hex_index >= hex_finish && column > 0)\n    {\n        ssl_printf(\"\\n\");\n    }\n}\n\n/**\n * Spit out a blob of data for diagnostics. The data is is a nice column format\n * for easy reading.\n *\n * @param format   [in]    The string (with possible embedded format characters)\n * @param size     [in]    The number of numbers to print\n * @param data     [in]    The start of data to use\n * @param ...      [in]    Any additional arguments\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR print_blob(const char *format, \n        const uint8_t *data, int size, ...)\n{\n//    int i;\n//    char tmp[80];\n//    va_list(ap);\n\n//    va_start(ap, size);\n//    sprintf(tmp, \"%s\\n\", format);\n//    vprintf(tmp, ap);\n//    print_hex_init(size);\n//    for (i = 0; i < size; i++)\n//    {\n//        print_hex(data[i]);\n//    }\n\n//    va_end(ap);\n//    TTY_FLUSH();\n}\n#elif defined(WIN32)\n/* VC6.0 doesn't handle variadic macros */\nEXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,\n        int size, ...) {}\n#endif\n\n#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)\n/* base64 to binary lookup table */\nstatic const uint8_t map[128] =\n{\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,\n    255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,\n    52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,\n    255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,\n    7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,\n    19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,\n    255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,\n    37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,\n    49,  50,  51, 255, 255, 255, 255, 255\n};\n\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR base64_decode(const char *in, int len,\n                    uint8_t *out, int *outlen)\n{\n    int g, t, x, y, z;\n    uint8_t c;\n    int ret = -1;\n\n    g = 3;\n    for (x = y = z = t = 0; x < len; x++)\n    {\n        if ((c = map[in[x]&0x7F]) == 0xff)\n            continue;\n\n        if (c == 254)   /* this is the end... */\n        {\n            c = 0;\n\n            if (--g < 0)\n                goto error;\n        }\n        else if (g != 3) /* only allow = at end */\n            goto error;\n\n        t = (t<<6) | c;\n\n        if (++y == 4)\n        {\n            out[z++] = (uint8_t)((t>>16)&255);\n\n            if (g > 1)\n                out[z++] = (uint8_t)((t>>8)&255);\n\n            if (g > 2)\n                out[z++] = (uint8_t)(t&255);\n\n            y = t = 0;\n        }\n\n        /* check that we don't go past the output buffer */\n        if (z > *outlen) \n            goto error;\n    }\n\n    if (y != 0)\n        goto error;\n\n    *outlen = z;\n    ret = 0;\n\nerror:\n#ifdef CONFIG_SSL_FULL_MODE\n    if (ret < 0)\n        ssl_printf(\"Error: Invalid base64\\n\"); //TTY_FLUSH();\n#endif\n    //TTY_FLUSH();\n    return ret;\n\n}\n#endif\n\n"
  },
  {
    "path": "app/ssl/crypto/ssl_hmac.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * HMAC implementation - This code was originally taken from RFC2104\n * See http://www.ietf.org/rfc/rfc2104.txt and\n * http://www.faqs.org/rfcs/rfc2202.html\n */\n\n//#include <string.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto.h\"\n\n/**\n * Perform HMAC-MD5\n * NOTE: does not handle keys larger than the block size.\n */\nvoid ICACHE_FLASH_ATTR ssl_hmac_md5(const uint8_t *msg, int length, const uint8_t *key, \n        int key_len, uint8_t *digest)\n{\n    MD5_CTX context;\n    uint8_t k_ipad[64];\n    uint8_t k_opad[64];\n    int i;\n\n    os_memset(k_ipad, 0, sizeof k_ipad);\n    os_memset(k_opad, 0, sizeof k_opad);\n    os_memcpy(k_ipad, key, key_len);\n    os_memcpy(k_opad, key, key_len);\n\n    for (i = 0; i < 64; i++) \n    {\n        k_ipad[i] ^= 0x36;\n        k_opad[i] ^= 0x5c;\n    }\n\n    MD5_Init(&context);\n    MD5_Update(&context, k_ipad, 64);\n    MD5_Update(&context, msg, length);\n    MD5_Final(digest, &context);\n    MD5_Init(&context);\n    MD5_Update(&context, k_opad, 64);\n    MD5_Update(&context, digest, MD5_SIZE);\n    MD5_Final(digest, &context);\n}\n\n/**\n * Perform HMAC-SHA1\n * NOTE: does not handle keys larger than the block size.\n */\nvoid ICACHE_FLASH_ATTR ssl_hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, \n        int key_len, uint8_t *digest)\n{\n    SHA1_CTX context;\n    uint8_t k_ipad[64];\n    uint8_t k_opad[64];\n    int i;\n\n    os_memset(k_ipad, 0, sizeof k_ipad);\n    os_memset(k_opad, 0, sizeof k_opad);\n    os_memcpy(k_ipad, key, key_len);\n    os_memcpy(k_opad, key, key_len);\n\n    for (i = 0; i < 64; i++) \n    {\n        k_ipad[i] ^= 0x36;\n        k_opad[i] ^= 0x5c;\n    }\n\n    SHA1_Init(&context);\n    SHA1_Update(&context, k_ipad, 64);\n    SHA1_Update(&context, msg, length);\n    SHA1_Final(digest, &context);\n    SHA1_Init(&context);\n    SHA1_Update(&context, k_opad, 64);\n    SHA1_Update(&context, digest, SHA1_SIZE);\n    SHA1_Final(digest, &context);\n}\n"
  },
  {
    "path": "app/ssl/crypto/ssl_md2.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n *  RFC 1115/1319 compliant MD2 implementation\n *  The MD2 algorithm was designed by Ron Rivest in 1989.\n *\n *  http://www.ietf.org/rfc/rfc1115.txt\n *  http://www.ietf.org/rfc/rfc1319.txt\n */\n\n//#include <string.h>\n//#include <stdio.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\n/**\n * This code is only here to enable the verification of Verisign root\n * certificates. So only enable it for verification mode.\n */\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n\nstatic const uint8_t PI_SUBST[256] =\n{\n    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36,\n    0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3,\n    0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C,\n    0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16,\n    0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E,\n    0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E,\n    0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2,\n    0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,\n    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E,\n    0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3,\n    0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56,\n    0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6,\n    0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D,\n    0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65,\n    0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0,\n    0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,\n    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C,\n    0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E,\n    0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81,\n    0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA,\n    0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88,\n    0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE,\n    0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58,\n    0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,\n    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99,\n    0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14\n};\n\n/*\n * MD2 context setup\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD2_Init(MD2_CTX *ctx)\n{\n    os_memset(ctx, 0, sizeof *ctx);\n}\n\nstatic void ICACHE_FLASH_ATTR md2_process(MD2_CTX *ctx)\n{\n    int i, j;\n    uint8_t t = 0;\n\n    for (i = 0; i < 16; i++)\n    {\n        ctx->state[i + 16] = ctx->buffer[i];\n        ctx->state[i + 32] = ctx->buffer[i] ^ ctx->state[i];\n    }\n\n    for (i = 0; i < 18; i++)\n    {\n        for (j = 0; j < 48; j++)\n            t = (ctx->state[j] ^= PI_SUBST[t]);\n\n        t = (t + i) & 0xFF;\n    }\n\n    t = ctx->cksum[15];\n\n    for (i = 0; i < 16; i++)\n        t = (ctx->cksum[i] ^= PI_SUBST[ctx->buffer[i] ^ t]);\n}\n\n/*\n * MD2 process buffer\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen)\n{\n    int fill;\n\n    while (ilen > 0)\n    {\n        if (ctx->left + ilen > 16)\n            fill = 16 - ctx->left;\n        else\n            fill = ilen;\n\n        os_memcpy(ctx->buffer + ctx->left, input, fill);\n\n        ctx->left += fill;\n        input += fill;\n        ilen  -= fill;\n\n        if (ctx->left == 16)\n        {\n            ctx->left = 0;\n            md2_process(ctx);\n        }\n    }\n}\n\n/*\n * MD2 final digest\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD2_Final(uint8_t *output, MD2_CTX *ctx)\n{\n    int i;\n    uint8_t x;\n\n    x = (uint8_t)(16 - ctx->left);\n\n    for (i = ctx->left; i < 16; i++)\n        ctx->buffer[i] = x;\n\n    md2_process(ctx);\n\n    os_memcpy(ctx->buffer, ctx->cksum, 16);\n    md2_process(ctx);\n\n    os_memcpy(output, ctx->state, 16);\n}\n\n#endif\n"
  },
  {
    "path": "app/ssl/crypto/ssl_md5.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * This file implements the MD5 algorithm as defined in RFC1321\n */\n\n//#include <string.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\n/* Constants for MD5Transform routine.\n */\n#define S11 7\n#define S12 12\n#define S13 17\n#define S14 22\n#define S21 5\n#define S22 9\n#define S23 14\n#define S24 20\n#define S31 4\n#define S32 11\n#define S33 16\n#define S34 23\n#define S41 6\n#define S42 10\n#define S43 15\n#define S44 21\n\n/* ----- static functions ----- */\nstatic void MD5Transform(uint32_t state[4], const uint8_t block[64]);\nstatic void Encode(uint8_t *output, uint32_t *input, uint32_t len);\nstatic void Decode(uint32_t *output, const uint8_t *input, uint32_t len);\n\nstatic const uint8_t PADDING[64] = \n{\n    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n};\n\n/* F, G, H and I are basic MD5 functions.\n */\n#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))\n#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))\n#define H(x, y, z) ((x) ^ (y) ^ (z))\n#define I(x, y, z) ((y) ^ ((x) | (~z)))\n\n/* ROTATE_LEFT rotates x left n bits.  */\n#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))\n\n/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.\n   Rotation is separate from addition to prevent recomputation.  */\n#define FF(a, b, c, d, x, s, ac) { \\\n    (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \\\n    (a) = ROTATE_LEFT ((a), (s)); \\\n    (a) += (b); \\\n  }\n#define GG(a, b, c, d, x, s, ac) { \\\n    (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \\\n    (a) = ROTATE_LEFT ((a), (s)); \\\n    (a) += (b); \\\n  }\n#define HH(a, b, c, d, x, s, ac) { \\\n    (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \\\n    (a) = ROTATE_LEFT ((a), (s)); \\\n    (a) += (b); \\\n  }\n#define II(a, b, c, d, x, s, ac) { \\\n    (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \\\n    (a) = ROTATE_LEFT ((a), (s)); \\\n    (a) += (b); \\\n  }\n\n/**\n * MD5 initialization - begins an MD5 operation, writing a new ctx.\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD5_Init(MD5_CTX *ctx)\n{\n    ctx->count[0] = ctx->count[1] = 0;\n\n    /* Load magic initialization constants.\n     */\n    ctx->state[0] = 0x67452301;\n    ctx->state[1] = 0xefcdab89;\n    ctx->state[2] = 0x98badcfe;\n    ctx->state[3] = 0x10325476;\n}\n\n/**\n * Accepts an array of octets as the next portion of the message.\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD5_Update(MD5_CTX *ctx, const uint8_t * msg, int len)\n{\n    uint32_t x;\n    int i, partLen;\n\n    /* Compute number of bytes mod 64 */\n    x = (uint32_t)((ctx->count[0] >> 3) & 0x3F);\n\n    /* Update number of bits */\n    if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3))\n        ctx->count[1]++;\n    ctx->count[1] += ((uint32_t)len >> 29);\n\n    partLen = 64 - x;\n\n    /* Transform as many times as possible.  */\n    if (len >= partLen) \n    {\n        os_memcpy(&ctx->buffer[x], msg, partLen);\n        MD5Transform(ctx->state, ctx->buffer);\n\n        for (i = partLen; i + 63 < len; i += 64)\n            MD5Transform(ctx->state, &msg[i]);\n\n        x = 0;\n    }\n    else\n        i = 0;\n\n    /* Buffer remaining input */\n    os_memcpy(&ctx->buffer[x], &msg[i], len-i);\n}\n\n/**\n * Return the 128-bit message digest into the user's array\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR MD5_Final(uint8_t *digest, MD5_CTX *ctx)\n{\n    uint8_t bits[8];\n    uint32_t x, padLen;\n\n    /* Save number of bits */\n    Encode(bits, ctx->count, 8);\n\n    /* Pad out to 56 mod 64.\n     */\n    x = (uint32_t)((ctx->count[0] >> 3) & 0x3f);\n    padLen = (x < 56) ? (56 - x) : (120 - x);\n    MD5_Update(ctx, PADDING, padLen);\n\n    /* Append length (before padding) */\n    MD5_Update(ctx, bits, 8);\n\n    /* Store state in digest */\n    Encode(digest, ctx->state, MD5_SIZE);\n}\n\n/**\n * MD5 basic transformation. Transforms state based on block.\n */\nstatic void ICACHE_FLASH_ATTR MD5Transform(uint32_t state[4], const uint8_t block[64])\n{\n    uint32_t a = state[0], b = state[1], c = state[2], \n             d = state[3], x[MD5_SIZE];\n\n    Decode(x, block, 64);\n\n    /* Round 1 */\n    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */\n    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */\n    FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */\n    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */\n    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */\n    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */\n    FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */\n    FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */\n    FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */\n    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */\n    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */\n    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */\n    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */\n    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */\n    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */\n    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */\n\n    /* Round 2 */\n    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */\n    GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */\n    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */\n    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */\n    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */\n    GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */\n    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */\n    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */\n    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */\n    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */\n    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */\n    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */\n    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */\n    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */\n    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */\n    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */\n\n    /* Round 3 */\n    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */\n    HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */\n    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */\n    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */\n    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */\n    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */\n    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */\n    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */\n    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */\n    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */\n    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */\n    HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */\n    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */\n    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */\n    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */\n    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */\n\n    /* Round 4 */\n    II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */\n    II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */\n    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */\n    II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */\n    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */\n    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */\n    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */\n    II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */\n    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */\n    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */\n    II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */\n    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */\n    II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */\n    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */\n    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */\n    II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */\n\n    state[0] += a;\n    state[1] += b;\n    state[2] += c;\n    state[3] += d;\n}\n\n/**\n * Encodes input (uint32_t) into output (uint8_t). Assumes len is\n *   a multiple of 4.\n */\nstatic void ICACHE_FLASH_ATTR Encode(uint8_t *output, uint32_t *input, uint32_t len)\n{\n    uint32_t i, j;\n\n    for (i = 0, j = 0; j < len; i++, j += 4) \n    {\n        output[j] = (uint8_t)(input[i] & 0xff);\n        output[j+1] = (uint8_t)((input[i] >> 8) & 0xff);\n        output[j+2] = (uint8_t)((input[i] >> 16) & 0xff);\n        output[j+3] = (uint8_t)((input[i] >> 24) & 0xff);\n    }\n}\n\n/**\n *  Decodes input (uint8_t) into output (uint32_t). Assumes len is\n *   a multiple of 4.\n */\nstatic void ICACHE_FLASH_ATTR Decode(uint32_t *output, const uint8_t *input, uint32_t len)\n{\n    uint32_t i, j;\n\n    for (i = 0, j = 0; j < len; i++, j += 4)\n        output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |\n            (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);\n}\n"
  },
  {
    "path": "app/ssl/crypto/ssl_rc4.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * An implementation of the RC4/ARC4 algorithm.\n * Originally written by Christophe Devine.\n */\n\n//#include <string.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto.h\"\n\n/**\n * Get ready for an encrypt/decrypt operation\n */\nvoid ICACHE_FLASH_ATTR RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length)\n{\n    int i, j = 0, k = 0, a;\n    uint8_t *m;\n\n    ctx->x = 0;\n    ctx->y = 0;\n    m = ctx->m;\n\n    for (i = 0; i < 256; i++)\n        m[i] = i;\n\n    for (i = 0; i < 256; i++)\n    {\n        a = m[i];\n        j = (uint8_t)(j + a + key[k]);\n        m[i] = m[j]; \n        m[j] = a;\n\n        if (++k >= length) \n            k = 0;\n    }\n}\n\n/**\n * Perform the encrypt/decrypt operation (can use it for either since\n * this is a stream cipher).\n * NOTE: *msg and *out must be the same pointer (performance tweak)\n */\nvoid ICACHE_FLASH_ATTR RC4_crypt(RC4_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)\n{ \n    int i;\n    uint8_t *m, x, y, a, b;\n\n    x = ctx->x;\n    y = ctx->y;\n    m = ctx->m;\n\n    for (i = 0; i < length; i++)\n    {\n        a = m[++x];\n        y += a;\n        m[x] = b = m[y];\n        m[y] = a;\n        out[i] ^= m[(uint8_t)(a + b)];\n    }\n\n    ctx->x = x;\n    ctx->y = y;\n}\n"
  },
  {
    "path": "app/ssl/crypto/ssl_rsa.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * Implements the RSA public encryption algorithm. Uses the bigint library to\n * perform its calculations.\n */\n\n//#include <stdio.h>\n//#include <string.h>\n//#include <time.h>\n//#include <stdlib.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\nvoid ICACHE_FLASH_ATTR RSA_priv_key_new(RSA_CTX **ctx, \n        const uint8_t *modulus, int mod_len,\n        const uint8_t *pub_exp, int pub_len,\n        const uint8_t *priv_exp, int priv_len\n#if CONFIG_BIGINT_CRT\n      , const uint8_t *p, int p_len,\n        const uint8_t *q, int q_len,\n        const uint8_t *dP, int dP_len,\n        const uint8_t *dQ, int dQ_len,\n        const uint8_t *qInv, int qInv_len\n#endif\n    )\n{\n    RSA_CTX *rsa_ctx;\n    BI_CTX *bi_ctx;\n    RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len);\n    rsa_ctx = *ctx;\n    bi_ctx = rsa_ctx->bi_ctx;\n    rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len);\n    bi_permanent(rsa_ctx->d);\n\n#ifdef CONFIG_BIGINT_CRT\n    rsa_ctx->p = bi_import(bi_ctx, p, p_len);\n    rsa_ctx->q = bi_import(bi_ctx, q, q_len);\n    rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len);\n    rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len);\n    rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len);\n    bi_permanent(rsa_ctx->dP);\n    bi_permanent(rsa_ctx->dQ);\n    bi_permanent(rsa_ctx->qInv);\n    bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET);\n    bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET);\n#endif\n}\n\nvoid ICACHE_FLASH_ATTR RSA_pub_key_new(RSA_CTX **ctx, \n        const uint8_t *modulus, int mod_len,\n        const uint8_t *pub_exp, int pub_len)\n{\n    RSA_CTX *rsa_ctx;\n    BI_CTX *bi_ctx;\n\n    if (*ctx)   /* if we load multiple certs, dump the old one */\n        RSA_free(*ctx);\n\n    bi_ctx = bi_initialize();\n    *ctx = (RSA_CTX *)os_zalloc(sizeof(RSA_CTX));\n    rsa_ctx = *ctx;\n    rsa_ctx->bi_ctx = bi_ctx;\n    rsa_ctx->num_octets = mod_len;\n    rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len);\n    bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET);\n    rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len);\n    bi_permanent(rsa_ctx->e);\n}\n\n/**\n * Free up any RSA context resources.\n */\nvoid ICACHE_FLASH_ATTR RSA_free(RSA_CTX *rsa_ctx)\n{\n    BI_CTX *bi_ctx;\n    if (rsa_ctx == NULL)                /* deal with ptrs that are null */\n        return;\n\n    bi_ctx = rsa_ctx->bi_ctx;\n\n    bi_depermanent(rsa_ctx->e);\n    bi_free(bi_ctx, rsa_ctx->e);\n    bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET);\n\n    if (rsa_ctx->d)\n    {\n        bi_depermanent(rsa_ctx->d);\n        bi_free(bi_ctx, rsa_ctx->d);\n#ifdef CONFIG_BIGINT_CRT\n        bi_depermanent(rsa_ctx->dP);\n        bi_depermanent(rsa_ctx->dQ);\n        bi_depermanent(rsa_ctx->qInv);\n        bi_free(bi_ctx, rsa_ctx->dP);\n        bi_free(bi_ctx, rsa_ctx->dQ);\n        bi_free(bi_ctx, rsa_ctx->qInv);\n        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET);\n        bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET);\n#endif\n    }\n\n    bi_terminate(bi_ctx);\n    os_free(rsa_ctx);\n}\n\n/**\n * @brief Use PKCS1.5 for decryption/verification.\n * @param ctx [in] The context\n * @param in_data [in] The data to encrypt (must be < modulus size-11)\n * @param out_data [out] The encrypted data.\n * @param is_decryption [in] Decryption or verify operation.\n * @return  The number of bytes that were originally encrypted. -1 on error.\n * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125\n */\nint ICACHE_FLASH_ATTR RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, \n                            uint8_t *out_data, int is_decryption)\n{\n    const int byte_size = ctx->num_octets;\n    int i, size;\n    bigint *decrypted_bi, *dat_bi;\n    uint8_t *block = (uint8_t *)os_malloc(byte_size);\n\n    os_memset(out_data, 0, byte_size); /* initialise */\n\n    /* decrypt */\n    dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size);\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n    decrypted_bi = is_decryption ?  /* decrypt or verify? */\n            RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi);\n#else   /* always a decryption */\n    decrypted_bi = RSA_private(ctx, dat_bi);\n#endif\n\n    /* convert to a normal block */\n    bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size);\n\n    i = 10; /* start at the first possible non-padded byte */\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n    if (is_decryption == 0) /* PKCS1.5 signing pads with \"0xff\"s */\n    {\n        while (block[i++] == 0xff && i < byte_size);\n\n        if (block[i-2] != 0xff)\n            i = byte_size;     /*ensure size is 0 */   \n    }\n    else                    /* PKCS1.5 encryption padding is random */\n#endif\n    {\n        while (block[i++] && i < byte_size);\n    }\n    size = byte_size - i;\n\n    /* get only the bit we want */\n    if (size > 0)\n        os_memcpy(out_data, &block[i], size);\n\n    os_free(block);\n    return size ? size : -1;\n}\n\n/**\n * Performs m = c^d mod n\n */\nbigint *ICACHE_FLASH_ATTR RSA_private(const RSA_CTX *c, bigint *bi_msg)\n{\n#ifdef CONFIG_BIGINT_CRT\n    return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv);\n#else\n    BI_CTX *ctx = c->bi_ctx;\n    ctx->mod_offset = BIGINT_M_OFFSET;\n    return bi_mod_power(ctx, bi_msg, c->d);\n#endif\n}\n\n#ifdef CONFIG_SSL_FULL_MODE\n/**\n * Used for diagnostics.\n */\nvoid ICACHE_FLASH_ATTR RSA_print(const RSA_CTX *rsa_ctx) \n{\n    if (rsa_ctx == NULL)\n        return;\n\n    ssl_printf(\"-----------------   RSA DEBUG   ----------------\\n\");\n    ssl_printf(\"Size:\\t%d\\n\", rsa_ctx->num_octets);\n    bi_print(\"Modulus\", rsa_ctx->m);\n    bi_print(\"Public Key\", rsa_ctx->e);\n    bi_print(\"Private Key\", rsa_ctx->d);\n}\n#endif\n\n#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)\n/**\n * Performs c = m^e mod n\n */\nbigint *ICACHE_FLASH_ATTR RSA_public(const RSA_CTX * c, bigint *bi_msg)\n{\n    c->bi_ctx->mod_offset = BIGINT_M_OFFSET;\n    return bi_mod_power(c->bi_ctx, bi_msg, c->e);\n}\n\n/**\n * Use PKCS1.5 for encryption/signing.\n * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125\n */\nint ICACHE_FLASH_ATTR RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, \n        uint8_t *out_data, int is_signing)\n{\n    int byte_size = ctx->num_octets;\n    int num_pads_needed = byte_size-in_len-3;\n    bigint *dat_bi, *encrypt_bi;\n\n    /* note: in_len+11 must be > byte_size */\n    out_data[0] = 0;     /* ensure encryption block is < modulus */\n\n    if (is_signing)\n    {\n        out_data[1] = 1;        /* PKCS1.5 signing pads with \"0xff\"'s */\n        os_memset(&out_data[2], 0xff, num_pads_needed);\n    }\n    else /* randomize the encryption padding with non-zero bytes */   \n    {\n        out_data[1] = 2;\n        get_random_NZ(num_pads_needed, &out_data[2]);\n    }\n\n    out_data[2+num_pads_needed] = 0;\n    os_memcpy(&out_data[3+num_pads_needed], in_data, in_len);\n\n    /* now encrypt it */\n    dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size);\n    encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : \n                              RSA_public(ctx, dat_bi);\n    bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size);\n\n    /* save a few bytes of memory */\n    bi_clear_cache(ctx->bi_ctx);\n    return byte_size;\n}\n\n#endif  /* CONFIG_SSL_CERT_VERIFICATION */\n"
  },
  {
    "path": "app/ssl/crypto/ssl_sha1.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995.\n * This code was originally taken from RFC3174\n */\n\n//#include <string.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\n/*\n *  Define the SHA1 circular left shift macro\n */\n#define SHA1CircularShift(bits,word) \\\n                (((word) << (bits)) | ((word) >> (32-(bits))))\n\n/* ----- static functions ----- */\nstatic void SHA1PadMessage(SHA1_CTX *ctx);\nstatic void SHA1ProcessMessageBlock(SHA1_CTX *ctx);\n\n/**\n * Initialize the SHA1 context \n */\nvoid ICACHE_FLASH_ATTR SHA1_Init(SHA1_CTX *ctx)\n{\n    ctx->Length_Low             = 0;\n    ctx->Length_High            = 0;\n    ctx->Message_Block_Index    = 0;\n    ctx->Intermediate_Hash[0]   = 0x67452301;\n    ctx->Intermediate_Hash[1]   = 0xEFCDAB89;\n    ctx->Intermediate_Hash[2]   = 0x98BADCFE;\n    ctx->Intermediate_Hash[3]   = 0x10325476;\n    ctx->Intermediate_Hash[4]   = 0xC3D2E1F0;\n}\n\n/**\n * Accepts an array of octets as the next portion of the message.\n */\nvoid ICACHE_FLASH_ATTR SHA1_Update(SHA1_CTX *ctx, const uint8_t *msg, int len)\n{\n    while (len--)\n    {\n        ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF);\n        ctx->Length_Low += 8;\n\n        if (ctx->Length_Low == 0)\n            ctx->Length_High++;\n\n        if (ctx->Message_Block_Index == 64)\n            SHA1ProcessMessageBlock(ctx);\n\n        msg++;\n    }\n}\n\n/**\n * Return the 160-bit message digest into the user's array\n */\nvoid ICACHE_FLASH_ATTR SHA1_Final(uint8_t *digest, SHA1_CTX *ctx)\n{\n    int i;\n\n    SHA1PadMessage(ctx);\n    os_memset(ctx->Message_Block, 0, 64);\n    ctx->Length_Low = 0;    /* and clear length */\n    ctx->Length_High = 0;\n\n    for  (i = 0; i < SHA1_SIZE; i++)\n    {\n        digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) );\n    }\n}\n\n/**\n * Process the next 512 bits of the message stored in the array.\n */\nstatic void ICACHE_FLASH_ATTR SHA1ProcessMessageBlock(SHA1_CTX *ctx)\n{\n    const uint32_t K[] =    {       /* Constants defined in SHA-1   */\n                            0x5A827999,\n                            0x6ED9EBA1,\n                            0x8F1BBCDC,\n                            0xCA62C1D6\n                            };\n    int        t;                 /* Loop counter                */\n    uint32_t      temp;              /* Temporary word value        */\n    uint32_t      W[80];             /* Word sequence               */\n    uint32_t      A, B, C, D, E;     /* Word buffers                */\n\n    /*\n     *  Initialize the first 16 words in the array W\n     */\n    for  (t = 0; t < 16; t++)\n    {\n        W[t] = ctx->Message_Block[t * 4] << 24;\n        W[t] |= ctx->Message_Block[t * 4 + 1] << 16;\n        W[t] |= ctx->Message_Block[t * 4 + 2] << 8;\n        W[t] |= ctx->Message_Block[t * 4 + 3];\n    }\n\n    for (t = 16; t < 80; t++)\n    {\n       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);\n    }\n\n    A = ctx->Intermediate_Hash[0];\n    B = ctx->Intermediate_Hash[1];\n    C = ctx->Intermediate_Hash[2];\n    D = ctx->Intermediate_Hash[3];\n    E = ctx->Intermediate_Hash[4];\n\n    for (t = 0; t < 20; t++)\n    {\n        temp =  SHA1CircularShift(5,A) +\n                ((B & C) | ((~B) & D)) + E + W[t] + K[0];\n        E = D;\n        D = C;\n        C = SHA1CircularShift(30,B);\n\n        B = A;\n        A = temp;\n    }\n\n    for (t = 20; t < 40; t++)\n    {\n        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];\n        E = D;\n        D = C;\n        C = SHA1CircularShift(30,B);\n        B = A;\n        A = temp;\n    }\n\n    for (t = 40; t < 60; t++)\n    {\n        temp = SHA1CircularShift(5,A) +\n               ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];\n        E = D;\n        D = C;\n        C = SHA1CircularShift(30,B);\n        B = A;\n        A = temp;\n    }\n\n    for (t = 60; t < 80; t++)\n    {\n        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];\n        E = D;\n        D = C;\n        C = SHA1CircularShift(30,B);\n        B = A;\n        A = temp;\n    }\n\n    ctx->Intermediate_Hash[0] += A;\n    ctx->Intermediate_Hash[1] += B;\n    ctx->Intermediate_Hash[2] += C;\n    ctx->Intermediate_Hash[3] += D;\n    ctx->Intermediate_Hash[4] += E;\n    ctx->Message_Block_Index = 0;\n}\n\n/*\n * According to the standard, the message must be padded to an even\n * 512 bits.  The first padding bit must be a '1'.  The last 64\n * bits represent the length of the original message.  All bits in\n * between should be 0.  This function will pad the message\n * according to those rules by filling the Message_Block array\n * accordingly.  It will also call the ProcessMessageBlock function\n * provided appropriately.  When it returns, it can be assumed that\n * the message digest has been computed.\n *\n * @param ctx [in, out] The SHA1 context\n */\nstatic void ICACHE_FLASH_ATTR SHA1PadMessage(SHA1_CTX *ctx)\n{\n    /*\n     *  Check to see if the current message block is too small to hold\n     *  the initial padding bits and length.  If so, we will pad the\n     *  block, process it, and then continue padding into a second\n     *  block.\n     */\n    if (ctx->Message_Block_Index > 55)\n    {\n        ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;\n        while(ctx->Message_Block_Index < 64)\n        {\n            ctx->Message_Block[ctx->Message_Block_Index++] = 0;\n        }\n\n        SHA1ProcessMessageBlock(ctx);\n\n        while (ctx->Message_Block_Index < 56)\n        {\n            ctx->Message_Block[ctx->Message_Block_Index++] = 0;\n        }\n    }\n    else\n    {\n        ctx->Message_Block[ctx->Message_Block_Index++] = 0x80;\n        while(ctx->Message_Block_Index < 56)\n        {\n\n            ctx->Message_Block[ctx->Message_Block_Index++] = 0;\n        }\n    }\n\n    /*\n     *  Store the message length as the last 8 octets\n     */\n    ctx->Message_Block[56] = ctx->Length_High >> 24;\n    ctx->Message_Block[57] = ctx->Length_High >> 16;\n    ctx->Message_Block[58] = ctx->Length_High >> 8;\n    ctx->Message_Block[59] = ctx->Length_High;\n    ctx->Message_Block[60] = ctx->Length_Low >> 24;\n    ctx->Message_Block[61] = ctx->Length_Low >> 16;\n    ctx->Message_Block[62] = ctx->Length_Low >> 8;\n    ctx->Message_Block[63] = ctx->Length_Low;\n    SHA1ProcessMessageBlock(ctx);\n}\n"
  },
  {
    "path": "app/ssl/ssl/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\n\nGEN_LIBS = libsslssl.a\n\nendif\n\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/ssl/ssl/ssl_asn1.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * Some primitive asn methods for extraction ASN.1 data.\n */\n\n//#include <stdio.h>\n//#include <stdlib.h>\n//#include <string.h>\n//#include <time.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto.h\"\n#include \"ssl/ssl_crypto_misc.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\nstruct tm\n{\n  int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */\n  int tm_min;                   /* Minutes.     [0-59] */\n  int tm_hour;                  /* Hours.       [0-23] */\n  int tm_mday;                  /* Day.         [1-31] */\n  int tm_mon;                   /* Month.       [0-11] */\n  int tm_year;                  /* Year - 1900.  */\n  int tm_wday;                  /* Day of week. [0-6] */\n  int tm_yday;                  /* Days in year.[0-365] */\n  int tm_isdst;                 /* DST.         [-1/0/1]*/\n\n#ifdef  __USE_BSD\n  long int tm_gmtoff;           /* Seconds east of UTC.  */\n  __const char *tm_zone;        /* Timezone abbreviation.  */\n#else\n  long int __tm_gmtoff;         /* Seconds east of UTC.  */\n  __const char *__tm_zone;      /* Timezone abbreviation.  */\n#endif\n};\n\n\n#define SIG_OID_PREFIX_SIZE 8\n#define SIG_IIS6_OID_SIZE   5\n#define SIG_SUBJECT_ALT_NAME_SIZE 3\n\n/* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */\nstatic const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] = \n{\n    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01\n};\n\nstatic const uint8_t sig_sha1WithRSAEncrypt[SIG_IIS6_OID_SIZE] =\n{\n    0x2b, 0x0e, 0x03, 0x02, 0x1d\n};\n\nstatic const uint8_t sig_subject_alt_name[SIG_SUBJECT_ALT_NAME_SIZE] =\n{\n    0x55, 0x1d, 0x11\n};\n\n/* CN, O, OU */\nstatic const uint8_t g_dn_types[] = { 3, 10, 11 };\n\nint ICACHE_FLASH_ATTR get_asn1_length(const uint8_t *buf, int *offset)\n{\n    int len, i;\n\n    if (!(buf[*offset] & 0x80)) /* short form */\n    {\n        len = buf[(*offset)++];\n    }\n    else  /* long form */\n    {\n        int length_bytes = buf[(*offset)++]&0x7f;\n        len = 0;\n        for (i = 0; i < length_bytes; i++)\n        {\n            len <<= 8;\n            len += buf[(*offset)++];\n        }\n    }\n\n    return len;\n}\n\n/**\n * Skip the ASN1.1 object type and its length. Get ready to read the object's\n * data.\n */\nint ICACHE_FLASH_ATTR asn1_next_obj(const uint8_t *buf, int *offset, int obj_type)\n{\n    if (buf[*offset] != obj_type)\n        return X509_NOT_OK;\n    (*offset)++;\n    return get_asn1_length(buf, offset);\n}\n\n/**\n * Skip over an ASN.1 object type completely. Get ready to read the next\n * object.\n */\nint ICACHE_FLASH_ATTR asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type)\n{\n    int len;\n\n    if (buf[*offset] != obj_type)\n        return X509_NOT_OK;\n    (*offset)++;\n    len = get_asn1_length(buf, offset);\n    *offset += len;\n    return 0;\n}\n\n/**\n * Read an integer value for ASN.1 data\n * Note: This function allocates memory which must be freed by the user.\n */\nint ICACHE_FLASH_ATTR asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object)\n{\n    int len;\n\n    if ((len = asn1_next_obj(buf, offset, ASN1_INTEGER)) < 0)\n        goto end_int_array;\n\n    if (len > 1 && buf[*offset] == 0x00)    /* ignore the negative byte */\n    {\n        len--;\n        (*offset)++;\n    }\n\n    *object = (uint8_t *)os_malloc(len);\n    os_memcpy(*object, &buf[*offset], len);\n    *offset += len;\n\nend_int_array:\n    return len;\n}\n\n/**\n * Get all the RSA private key specifics from an ASN.1 encoded file \n */\nint ICACHE_FLASH_ATTR asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx)\n{\n    int offset = 7;\n    uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL;\n    int mod_len, priv_len, pub_len;\n#ifdef CONFIG_BIGINT_CRT\n    uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL;\n    int p_len, q_len, dP_len, dQ_len, qInv_len;\n#endif\n\n    /* not in der format */\n    if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"Error: This is not a valid ASN.1 file\\n\");\n#endif\n        return X509_INVALID_PRIV_KEY;\n    }\n\n    /* Use the private key to mix up the RNG if possible. */\n    RNG_custom_init(buf, len);\n\n    mod_len = asn1_get_int(buf, &offset, &modulus);\n    pub_len = asn1_get_int(buf, &offset, &pub_exp);\n    priv_len = asn1_get_int(buf, &offset, &priv_exp);\n\n    if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0)\n        return X509_INVALID_PRIV_KEY;\n\n#ifdef CONFIG_BIGINT_CRT\n    p_len = asn1_get_int(buf, &offset, &p);\n    q_len = asn1_get_int(buf, &offset, &q);\n    dP_len = asn1_get_int(buf, &offset, &dP);\n    dQ_len = asn1_get_int(buf, &offset, &dQ);\n    qInv_len = asn1_get_int(buf, &offset, &qInv);\n\n    if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0)\n        return X509_INVALID_PRIV_KEY;\n\n    RSA_priv_key_new(rsa_ctx, \n            modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len,\n            p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len);\n\n    os_free(p);\n    os_free(q);\n    os_free(dP);\n    os_free(dQ);\n    os_free(qInv);\n#else\n    RSA_priv_key_new(rsa_ctx, \n            modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len);\n#endif\n\n    os_free(modulus);\n    os_free(priv_exp);\n    os_free(pub_exp);\n    return X509_OK;\n}\n\n/**\n * Get the time of a certificate. Ignore hours/minutes/seconds.\n */\nstatic int ICACHE_FLASH_ATTR asn1_get_utc_time(const uint8_t *buf, int *offset, time_t *t)\n{\n    int ret = X509_NOT_OK, len, t_offset;\n    struct tm tm;\n\n    if (buf[(*offset)++] != ASN1_UTC_TIME)\n        goto end_utc_time;\n\n    len = get_asn1_length(buf, offset);\n    t_offset = *offset;\n\n    os_memset(&tm, 0, sizeof(struct tm));\n    tm.tm_year = (buf[t_offset] - '0')*10 + (buf[t_offset+1] - '0');\n\n    if (tm.tm_year <= 50)    /* 1951-2050 thing */\n    {\n        tm.tm_year += 100;\n    }\n\n    tm.tm_mon = (buf[t_offset+2] - '0')*10 + (buf[t_offset+3] - '0') - 1;\n    tm.tm_mday = (buf[t_offset+4] - '0')*10 + (buf[t_offset+5] - '0');\n\n// wujg : pass compile first\n//    *t = mktime(&tm);\n    *offset += len;\n    ret = X509_OK;\n\nend_utc_time:\n    return ret;\n}\n\n/**\n * Get the version type of a certificate (which we don't actually care about)\n */\nint ICACHE_FLASH_ATTR asn1_version(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)\n{\n    int ret = X509_NOT_OK;\n\n    (*offset) += 2;        /* get past explicit tag */\n    if (asn1_skip_obj(cert, offset, ASN1_INTEGER))\n        goto end_version;\n\n    ret = X509_OK;\nend_version:\n    return ret;\n}\n\n/**\n * Retrieve the notbefore and notafter certificate times.\n */\nint ICACHE_FLASH_ATTR asn1_validity(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)\n{\n    return (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||\n              asn1_get_utc_time(cert, offset, &x509_ctx->not_before) ||\n              asn1_get_utc_time(cert, offset, &x509_ctx->not_after));\n}\n\n/**\n * Get the components of a distinguished name \n */\nstatic int ICACHE_FLASH_ATTR asn1_get_oid_x520(const uint8_t *buf, int *offset)\n{\n    int dn_type = 0;\n    int len;\n\n    if ((len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)\n        goto end_oid;\n\n    /* expect a sequence of 2.5.4.[x] where x is a one of distinguished name \n       components we are interested in. */\n    if (len == 3 && buf[(*offset)++] == 0x55 && buf[(*offset)++] == 0x04)\n        dn_type = buf[(*offset)++];\n    else\n    {\n        *offset += len;     /* skip over it */\n    }\n\nend_oid:\n    return dn_type;\n}\n\n/**\n * Obtain an ASN.1 printable string type.\n */\nstatic int ICACHE_FLASH_ATTR asn1_get_printable_str(const uint8_t *buf, int *offset, char **str)\n{\n    int len = X509_NOT_OK;\n    int asn1_type = buf[*offset];\n\n    /* some certs have this awful crud in them for some reason */\n    if (asn1_type != ASN1_PRINTABLE_STR &&  \n            asn1_type != ASN1_PRINTABLE_STR2 &&  \n            asn1_type != ASN1_TELETEX_STR &&  \n            asn1_type != ASN1_IA5_STR &&  \n            asn1_type != ASN1_UNICODE_STR)\n        goto end_pnt_str;\n\n    (*offset)++;\n    len = get_asn1_length(buf, offset);\n\n    if (asn1_type == ASN1_UNICODE_STR)\n    {\n        int i;\n        *str = (char *)os_malloc(len/2+1);     /* allow for null */\n\n        for (i = 0; i < len; i += 2)\n            (*str)[i/2] = buf[*offset + i + 1];\n\n        (*str)[len/2] = 0;                  /* null terminate */\n    }\n    else\n    {\n        *str = (char *)os_malloc(len+1);       /* allow for null */\n        os_memcpy(*str, &buf[*offset], len);\n        (*str)[len] = 0;                    /* null terminate */\n    }\n\n    *offset += len;\n\nend_pnt_str:\n    return len;\n}\n\n/**\n * Get the subject name (or the issuer) of a certificate.\n */\nint ICACHE_FLASH_ATTR asn1_name(const uint8_t *cert, int *offset, char *dn[])\n{\n    int ret = X509_NOT_OK;\n    int dn_type;\n    char *tmp;\n\n    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)\n        goto end_name;\n\n    while (asn1_next_obj(cert, offset, ASN1_SET) >= 0)\n    {\n        int i, found = 0;\n\n        if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||\n               (dn_type = asn1_get_oid_x520(cert, offset)) < 0)\n            goto end_name;\n\n        tmp = NULL;\n\n        if (asn1_get_printable_str(cert, offset, &tmp) < 0)\n        {\n            os_free(tmp);\n            goto end_name;\n        }\n\n        /* find the distinguished named type */\n        for (i = 0; i < X509_NUM_DN_TYPES; i++)\n        {\n            if (dn_type == g_dn_types[i])\n            {\n                if (dn[i] == NULL)\n                {\n                    dn[i] = tmp;\n                    found = 1;\n                    break;\n                }\n            }\n        }\n\n        if (found == 0) /* not found so get rid of it */\n        {\n            os_free(tmp);\n        }\n    }\n\n    ret = X509_OK;\nend_name:\n    return ret;\n}\n\n/**\n * Read the modulus and public exponent of a certificate.\n */\nint ICACHE_FLASH_ATTR asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)\n{\n    int ret = X509_NOT_OK, mod_len, pub_len;\n    uint8_t *modulus = NULL, *pub_exp = NULL;\n\n    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 ||\n            asn1_skip_obj(cert, offset, ASN1_SEQUENCE) ||\n            asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0)\n        goto end_pub_key;\n\n    (*offset)++;        /* ignore the padding bit field */\n\n    if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0)\n        goto end_pub_key;\n\n    mod_len = asn1_get_int(cert, offset, &modulus);\n    pub_len = asn1_get_int(cert, offset, &pub_exp);\n\n    RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len);\n\n    os_free(modulus);\n    os_free(pub_exp);\n    ret = X509_OK;\n\nend_pub_key:\n    return ret;\n}\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n/**\n * Read the signature of the certificate.\n */\nint ICACHE_FLASH_ATTR asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx)\n{\n    int ret = X509_NOT_OK;\n\n    if (cert[(*offset)++] != ASN1_BIT_STRING)\n        goto end_sig;\n\n    x509_ctx->sig_len = get_asn1_length(cert, offset)-1;\n    (*offset)++;            /* ignore bit string padding bits */\n    x509_ctx->signature = (uint8_t *)os_malloc(x509_ctx->sig_len);\n    os_memcpy(x509_ctx->signature, &cert[*offset], x509_ctx->sig_len);\n    *offset += x509_ctx->sig_len;\n    ret = X509_OK;\n\nend_sig:\n    return ret;\n}\n\n/*\n * Compare 2 distinguished name components for equality \n * @return 0 if a match\n */\nstatic int ICACHE_FLASH_ATTR asn1_compare_dn_comp(const char *dn1, const char *dn2)\n{\n    int ret;\n\n    if (dn1 == NULL && dn2 == NULL)\n        ret = 0;\n    else\n        ret = (dn1 && dn2) ? os_strcmp(dn1, dn2) : 1;\n\n    return ret;\n}\n\n/**\n * Clean up all of the CA certificates.\n */\nvoid ICACHE_FLASH_ATTR remove_ca_certs(CA_CERT_CTX *ca_cert_ctx)\n{\n    int i = 0;\n\n    if (ca_cert_ctx == NULL)\n        return;\n\n    while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])\n    {\n        x509_free(ca_cert_ctx->cert[i]);\n        ca_cert_ctx->cert[i++] = NULL;\n    }\n\n    os_free(ca_cert_ctx);\n}\n\n/*\n * Compare 2 distinguished names for equality \n * @return 0 if a match\n */\nint ICACHE_FLASH_ATTR asn1_compare_dn(char * const dn1[], char * const dn2[])\n{\n    int i;\n\n    for (i = 0; i < X509_NUM_DN_TYPES; i++)\n    {\n        if (asn1_compare_dn_comp(dn1[i], dn2[i]))\n            return 1;\n    }\n\n    return 0;       /* all good */\n}\n\nint ICACHE_FLASH_ATTR asn1_find_oid(const uint8_t* cert, int* offset, \n                    const uint8_t* oid, int oid_length)\n{\n    int seqlen;\n    if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0)\n    {\n        int end = *offset + seqlen;\n\n        while (*offset < end)\n        {\n            int type = cert[(*offset)++];\n            int length = get_asn1_length(cert, offset);\n            int noffset = *offset + length;\n\n            if (type == ASN1_SEQUENCE)\n            {\n                type = cert[(*offset)++];\n                length = get_asn1_length(cert, offset);\n\n                if (type == ASN1_OID && length == oid_length && \n                              os_memcmp(cert + *offset, oid, oid_length) == 0)\n                {\n                    *offset += oid_length;\n                    return 1;\n                }\n            }\n\n            *offset = noffset;\n        }\n    }\n\n    return 0;\n}\n\nint ICACHE_FLASH_ATTR asn1_find_subjectaltname(const uint8_t* cert, int offset)\n{\n    if (asn1_find_oid(cert, &offset, sig_subject_alt_name, \n                                SIG_SUBJECT_ALT_NAME_SIZE))\n    {\n        return offset;\n    }\n\n    return 0;\n}\n\n#endif /* CONFIG_SSL_CERT_VERIFICATION */\n\n/**\n * Read the signature type of the certificate. We only support RSA-MD5 and\n * RSA-SHA1 signature types.\n */\nint ICACHE_FLASH_ATTR asn1_signature_type(const uint8_t *cert, \n                                int *offset, X509_CTX *x509_ctx)\n{\n    int ret = X509_NOT_OK, len;\n\n    if (cert[(*offset)++] != ASN1_OID)\n        goto end_check_sig;\n\n    len = get_asn1_length(cert, offset);\n\n    if (len == 5 && os_memcmp(sig_sha1WithRSAEncrypt, &cert[*offset], \n                                    SIG_IIS6_OID_SIZE) == 0)\n    {\n        x509_ctx->sig_type = SIG_TYPE_SHA1;\n    }\n    else\n    {\n        if (os_memcmp(sig_oid_prefix, &cert[*offset], SIG_OID_PREFIX_SIZE))\n            goto end_check_sig;     /* unrecognised cert type */\n\n        x509_ctx->sig_type = cert[*offset + SIG_OID_PREFIX_SIZE];\n    }\n\n    *offset += len;\n    asn1_skip_obj(cert, offset, ASN1_NULL); /* if it's there */\n    ret = X509_OK;\n\nend_check_sig:\n    return ret;\n}\n\n"
  },
  {
    "path": "app/ssl/ssl/ssl_gen_cert.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include \"ssl/ssl_config.h\"\n\n#ifdef CONFIG_SSL_GENERATE_X509_CERT\n#include <string.h>\n#include <stdlib.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_ssl.h\"\n\n/**\n * Generate a basic X.509 certificate\n */\n\nstatic uint8_t ICACHE_FLASH_ATTR set_gen_length(int len, uint8_t *buf, int *offset)\n{\n    if (len < 0x80) /* short form */\n    {\n        buf[(*offset)++] = len;\n        return 1;\n    }\n    else /* long form */\n    {\n        int i, length_bytes = 0;\n\n        if (len & 0x00FF0000)\n            length_bytes = 3;\n        else if (len & 0x0000FF00)\n            length_bytes = 2;\n        else if (len & 0x000000FF)\n            length_bytes = 1;\n            \n        buf[(*offset)++] = 0x80 + length_bytes;\n\n        for (i = length_bytes-1; i >= 0; i--)\n        {\n            buf[*offset+i] = len & 0xFF;\n            len >>= 8;\n        }\n\n        *offset += length_bytes;\n        return length_bytes+1;\n    }\n}\n\nstatic int ICACHE_FLASH_ATTR pre_adjust_with_size(uint8_t type,\n        int *seq_offset, uint8_t *buf, int *offset)\n{\n    buf[(*offset)++] = type;\n    *seq_offset = *offset;\n    *offset += 4;   /* fill in later */\n    return *offset;\n}\n\nstatic void ICACHE_FLASH_ATTR adjust_with_size(int seq_size, int seq_start, \n                uint8_t *buf, int *offset)\n{\n    uint8_t seq_byte_size; \n    int orig_seq_size = seq_size;\n    int orig_seq_start = seq_start;\n\n    seq_size = *offset-seq_size;\n    seq_byte_size = set_gen_length(seq_size, buf, &seq_start);\n\n    if (seq_byte_size != 4)\n    {\n        memmove(&buf[orig_seq_start+seq_byte_size], \n                &buf[orig_seq_size], seq_size);\n        *offset -= 4-seq_byte_size;\n    }\n}\n\nstatic void ICACHE_FLASH_ATTR gen_serial_number(uint8_t *buf, int *offset)\n{\n    static const uint8_t ser_oid[] = { ASN1_INTEGER, 1, 0x7F };\n    memcpy(&buf[*offset], ser_oid , sizeof(ser_oid));\n    *offset += sizeof(ser_oid);\n}\n\nstatic void ICACHE_FLASH_ATTR gen_signature_alg(uint8_t *buf, int *offset)\n{\n    /* OBJECT IDENTIFIER sha1withRSAEncryption (1 2 840 113549 1 1 5) */\n    static const uint8_t sig_oid[] = \n    {\n        ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09, \n        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,\n        ASN1_NULL, 0x00\n    };\n\n    memcpy(&buf[*offset], sig_oid, sizeof(sig_oid));\n    *offset += sizeof(sig_oid);\n}\n\nstatic int ICACHE_FLASH_ATTR gen_dn(const char *name, uint8_t dn_type, \n                        uint8_t *buf, int *offset)\n{\n    int ret = X509_OK;\n    int name_size = strlen(name);\n\n    if (name_size > 0x70)    /* just too big */\n    {\n        ret = X509_NOT_OK;\n        goto error;\n    }\n\n    buf[(*offset)++] = ASN1_SET;\n    set_gen_length(9+name_size, buf, offset);\n    buf[(*offset)++] = ASN1_SEQUENCE;\n    set_gen_length(7+name_size, buf, offset);\n    buf[(*offset)++] = ASN1_OID;\n    buf[(*offset)++] = 3;\n    buf[(*offset)++] = 0x55;\n    buf[(*offset)++] = 0x04;\n    buf[(*offset)++] = dn_type;\n    buf[(*offset)++] = ASN1_PRINTABLE_STR;\n    buf[(*offset)++] = name_size;\n    strcpy(&buf[*offset], name);\n    *offset += name_size;\n\nerror:\n    return ret;\n}\n\nstatic int ICACHE_FLASH_ATTR gen_issuer(const char * dn[], uint8_t *buf, int *offset)\n{\n    int ret = X509_OK;\n    int seq_offset;\n    int seq_size = pre_adjust_with_size(\n                            ASN1_SEQUENCE, &seq_offset, buf, offset);\n    char fqdn[128]; \n\n    /* we need the common name, so if not configured, work out the fully\n     * qualified domain name */\n    if (dn[X509_COMMON_NAME] == NULL || strlen(dn[X509_COMMON_NAME]) == 0)\n    {\n        int fqdn_len;\n        gethostname(fqdn, sizeof(fqdn));\n        fqdn_len = strlen(fqdn);\n        fqdn[fqdn_len++] = '.';\n        getdomainname(&fqdn[fqdn_len], sizeof(fqdn)-fqdn_len);\n        fqdn_len = strlen(fqdn);\n\n        if (fqdn[fqdn_len-1] == '.')    /* ensure '.' is not last char */\n            fqdn[fqdn_len-1] = 0;\n\n        dn[X509_COMMON_NAME] = fqdn;\n    }\n\n    if ((ret = gen_dn(dn[X509_COMMON_NAME], 3, buf, offset)))\n        goto error;\n\n    if (dn[X509_ORGANIZATION] != NULL && strlen(dn[X509_ORGANIZATION]) > 0)\n    {\n        if ((ret = gen_dn(dn[X509_ORGANIZATION], 10, buf, offset)))\n            goto error;\n    }\n\n    if (dn[X509_ORGANIZATIONAL_UNIT] != NULL &&\n                                strlen(dn[X509_ORGANIZATIONAL_UNIT]) > 0)\n    {\n        if ((ret = gen_dn(dn[X509_ORGANIZATIONAL_UNIT], 11, buf, offset)))\n            goto error;\n    }\n\n    adjust_with_size(seq_size, seq_offset, buf, offset);\n\nerror:\n    return ret;\n}\n\nstatic void ICACHE_FLASH_ATTR gen_utc_time(uint8_t *buf, int *offset)\n{\n    static const uint8_t time_seq[] = \n    {\n        ASN1_SEQUENCE, 30, \n        ASN1_UTC_TIME, 13, \n        '0', '7', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z', \n        ASN1_UTC_TIME, 13,  /* make it good for 30 or so years */\n        '3', '8', '0', '1', '0', '1', '0', '0', '0', '0', '0', '0', 'Z'\n    };\n\n    /* fixed time */\n    memcpy(&buf[*offset], time_seq, sizeof(time_seq));\n    *offset += sizeof(time_seq);\n}\n\nstatic void ICACHE_FLASH_ATTR gen_pub_key2(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)\n{\n    static const uint8_t pub_key_seq[] = \n    {\n        ASN1_INTEGER, 0x03, 0x01, 0x00, 0x01 /* INTEGER 65537 */\n    };\n\n    int seq_offset;\n    int pub_key_size = rsa_ctx->num_octets;\n    uint8_t *block = (uint8_t *)alloca(pub_key_size);\n    int seq_size = pre_adjust_with_size(\n                            ASN1_SEQUENCE, &seq_offset, buf, offset);\n    buf[(*offset)++] = ASN1_INTEGER;\n    bi_export(rsa_ctx->bi_ctx, rsa_ctx->m, block, pub_key_size);\n\n    if (*block & 0x80)  /* make integer positive */\n    {\n        set_gen_length(pub_key_size+1, buf, offset);\n        buf[(*offset)++] = 0;\n    }\n    else\n        set_gen_length(pub_key_size, buf, offset);\n\n    memcpy(&buf[*offset], block, pub_key_size);\n    *offset += pub_key_size;\n    memcpy(&buf[*offset], pub_key_seq, sizeof(pub_key_seq));\n    *offset += sizeof(pub_key_seq);\n    adjust_with_size(seq_size, seq_offset, buf, offset);\n}\n\nstatic void ICACHE_FLASH_ATTR gen_pub_key1(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)\n{\n    int seq_offset;\n    int seq_size = pre_adjust_with_size(\n                            ASN1_BIT_STRING, &seq_offset, buf, offset);\n    buf[(*offset)++] = 0;   /* bit string is multiple of 8 */\n    gen_pub_key2(rsa_ctx, buf, offset);\n    adjust_with_size(seq_size, seq_offset, buf, offset);\n}\n\nstatic void ICACHE_FLASH_ATTR gen_pub_key(const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset)\n{\n    /*  OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) */\n    static const uint8_t rsa_enc_oid[] =\n    {\n        ASN1_SEQUENCE, 0x0d, ASN1_OID, 0x09,\n        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,\n        ASN1_NULL, 0x00\n    };\n\n    int seq_offset;\n    int seq_size = pre_adjust_with_size(\n                            ASN1_SEQUENCE, &seq_offset, buf, offset);\n\n    memcpy(&buf[*offset], rsa_enc_oid, sizeof(rsa_enc_oid));\n    *offset += sizeof(rsa_enc_oid);\n    gen_pub_key1(rsa_ctx, buf, offset);\n    adjust_with_size(seq_size, seq_offset, buf, offset);\n}\n\nstatic void ICACHE_FLASH_ATTR gen_signature(const RSA_CTX *rsa_ctx, const uint8_t *sha_dgst, \n                        uint8_t *buf, int *offset)\n{\n    static const uint8_t asn1_sig[] = \n    {\n        ASN1_SEQUENCE,  0x21, ASN1_SEQUENCE, 0x09, ASN1_OID, 0x05, \n        0x2b, 0x0e, 0x03, 0x02, 0x1a, /* sha1 (1 3 14 3 2 26) */\n        ASN1_NULL, 0x00, ASN1_OCTET_STRING, 0x14 \n    };\n\n    uint8_t *enc_block = (uint8_t *)alloca(rsa_ctx->num_octets);\n    uint8_t *block = (uint8_t *)alloca(sizeof(asn1_sig) + SHA1_SIZE);\n    int sig_size;\n\n    /* add the digest as an embedded asn.1 sequence */\n    memcpy(block, asn1_sig, sizeof(asn1_sig));\n    memcpy(&block[sizeof(asn1_sig)], sha_dgst, SHA1_SIZE);\n\n    sig_size = RSA_encrypt(rsa_ctx, block, \n                            sizeof(asn1_sig) + SHA1_SIZE, enc_block, 1);\n\n    buf[(*offset)++] = ASN1_BIT_STRING;\n    set_gen_length(sig_size+1, buf, offset);\n    buf[(*offset)++] = 0;   /* bit string is multiple of 8 */\n    memcpy(&buf[*offset], enc_block, sig_size);\n    *offset += sig_size;\n}\n\nstatic int ICACHE_FLASH_ATTR gen_tbs_cert(const char * dn[],\n                    const RSA_CTX *rsa_ctx, uint8_t *buf, int *offset,\n                    uint8_t *sha_dgst)\n{\n    int ret = X509_OK;\n    SHA1_CTX sha_ctx;\n    int seq_offset;\n    int begin_tbs = *offset;\n    int seq_size = pre_adjust_with_size(\n                        ASN1_SEQUENCE, &seq_offset, buf, offset);\n\n    gen_serial_number(buf, offset);\n    gen_signature_alg(buf, offset);\n\n    /* CA certicate issuer */\n    if ((ret = gen_issuer(dn, buf, offset)))\n        goto error;\n\n    gen_utc_time(buf, offset);\n\n    /* certificate issuer */\n    if ((ret = gen_issuer(dn, buf, offset)))\n        goto error;\n\n    gen_pub_key(rsa_ctx, buf, offset);\n    adjust_with_size(seq_size, seq_offset, buf, offset);\n\n    SHA1_Init(&sha_ctx);\n    SHA1_Update(&sha_ctx, &buf[begin_tbs], *offset-begin_tbs);\n    SHA1_Final(sha_dgst, &sha_ctx);\n\nerror:\n    return ret;\n}\n\n/**\n * Create a new certificate.\n */\nEXP_FUNC int ICACHE_FLASH_ATTR STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data)\n{\n    int ret = X509_OK, offset = 0, seq_offset;\n    /* allocate enough space to load a new certificate */\n    uint8_t *buf = (uint8_t *)alloca(ssl_ctx->rsa_ctx->num_octets*2 + 512);\n    uint8_t sha_dgst[SHA1_SIZE];\n    int seq_size = pre_adjust_with_size(ASN1_SEQUENCE, \n                                    &seq_offset, buf, &offset);\n\n    if ((ret = gen_tbs_cert(dn, ssl_ctx->rsa_ctx, buf, &offset, sha_dgst)) < 0)\n        goto error;\n\n    gen_signature_alg(buf, &offset);\n    gen_signature(ssl_ctx->rsa_ctx, sha_dgst, buf, &offset);\n    adjust_with_size(seq_size, seq_offset, buf, &offset);\n    *cert_data = (uint8_t *)os_malloc(offset); /* create the exact memory for it */\n    memcpy(*cert_data, buf, offset);\n\nerror:\n    return ret < 0 ? ret : offset;\n}\n\n#endif\n\n"
  },
  {
    "path": "app/ssl/ssl/ssl_loader.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * Load certificates/keys into memory. These can be in many different formats.\n * PEM support and other formats can be processed here.\n *\n * The PEM private keys may be optionally encrypted with AES128 or AES256. \n * The encrypted PEM keys were generated with something like:\n *\n * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512\n */\n\n//#include <stdlib.h>\n//#include <string.h>\n//#include <stdio.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_ssl.h\"\n\nstatic int do_obj(SSL_CTX *ssl_ctx, int obj_type, \n                    SSLObjLoader *ssl_obj, const char *password);\n#ifdef CONFIG_SSL_HAS_PEM\nstatic int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, \n                        SSLObjLoader *ssl_obj, const char *password);\n#endif\n\n/*\n * Load a file into memory that is in binary DER (or ascii PEM) format.\n */\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, \n                            const char *filename, const char *password)\n{\n#ifndef CONFIG_SSL_SKELETON_MODE\n    static const char * const begin = \"-----BEGIN\";\n    int ret = SSL_OK;\n    SSLObjLoader *ssl_obj = NULL;\n\n    if (filename == NULL)\n    {\n        ret = SSL_ERROR_INVALID_KEY;\n        goto error;\n    }\n\n    ssl_obj = (SSLObjLoader *)os_zalloc(sizeof(SSLObjLoader));\n    ssl_obj->len = get_file(filename, &ssl_obj->buf); \n    if (ssl_obj->len <= 0)\n    {\n        ret = SSL_ERROR_INVALID_KEY;\n        goto error;\n    }\n\n    /* is the file a PEM file? */\n    if ((char *)os_strstr((const char *)ssl_obj->buf, begin) != NULL)\n    {\n#ifdef CONFIG_SSL_HAS_PEM\n        ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password);\n#else\n        ssl_printf(unsupported_str);\n        ret = SSL_ERROR_NOT_SUPPORTED;\n#endif\n    }\n    else\n        ret = do_obj(ssl_ctx, obj_type, ssl_obj, password);\n\nerror:\n    ssl_obj_free(ssl_obj);\n    return ret;\n#else\n    ssl_printf(unsupported_str);\n    return SSL_ERROR_NOT_SUPPORTED;\n#endif /* CONFIG_SSL_SKELETON_MODE */\n}\n\n/*\n * Transfer binary data into the object loader.\n */\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type, \n        const uint8_t *data, int len, const char *password)\n{\n    int ret;\n    SSLObjLoader *ssl_obj;\n\n    ssl_obj = (SSLObjLoader *)os_zalloc(sizeof(SSLObjLoader));\n    ssl_obj->buf = (uint8_t *)os_malloc(len);\n    os_memcpy(ssl_obj->buf, data, len);\n    ssl_obj->len = len;\n    ret = do_obj(ssl_ctx, mem_type, ssl_obj, password);\n    ssl_obj_free(ssl_obj);\n    return ret;\n}\n\n/*\n * Actually work out what we are doing \n */\nstatic int ICACHE_FLASH_ATTR do_obj(SSL_CTX *ssl_ctx, int obj_type, \n                    SSLObjLoader *ssl_obj, const char *password)\n{\n    int ret = SSL_OK;\n\n    switch (obj_type)\n    {\n        case SSL_OBJ_RSA_KEY:\n            ret = add_private_key(ssl_ctx, ssl_obj);\n            break;\n\n        case SSL_OBJ_X509_CERT:\n            ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len);\n            break;\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n        case SSL_OBJ_X509_CACERT:\n            add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len);\n            break;\n#endif\n\n#ifdef CONFIG_SSL_USE_PKCS12\n        case SSL_OBJ_PKCS8:\n            ret = pkcs8_decode(ssl_ctx, ssl_obj, password);\n            break;\n\n        case SSL_OBJ_PKCS12:\n            ret = pkcs12_decode(ssl_ctx, ssl_obj, password);\n            break;\n#endif\n        default:\n            ssl_printf(unsupported_str);\n            ret = SSL_ERROR_NOT_SUPPORTED;\n            break;\n    }\n\n    return ret;\n}\n\n/*\n * Clean up our mess.\n */\nvoid ICACHE_FLASH_ATTR ssl_obj_free(SSLObjLoader *ssl_obj)\n{\n    if (ssl_obj)\n    {\n        os_free(ssl_obj->buf);\n        os_free(ssl_obj);\n    }\n}\n\n/*\n * Support for PEM encoded keys/certificates.\n */\n#ifdef CONFIG_SSL_HAS_PEM\n\n#define NUM_PEM_TYPES               4\n#define IV_SIZE                     16\n#define IS_RSA_PRIVATE_KEY          0\n#define IS_ENCRYPTED_PRIVATE_KEY    1\n#define IS_PRIVATE_KEY              2\n#define IS_CERTIFICATE              3\n\nstatic const char * const begins[NUM_PEM_TYPES] =\n{\n    \"-----BEGIN RSA PRIVATE KEY-----\",\n    \"-----BEGIN ENCRYPTED PRIVATE KEY-----\",\n    \"-----BEGIN PRIVATE KEY-----\",\n    \"-----BEGIN CERTIFICATE-----\",\n};\n\nstatic const char * const ends[NUM_PEM_TYPES] =\n{\n    \"-----END RSA PRIVATE KEY-----\",\n    \"-----END ENCRYPTED PRIVATE KEY-----\",\n    \"-----END PRIVATE KEY-----\",\n    \"-----END CERTIFICATE-----\",\n};\n\nstatic const char * const aes_str[2] =\n{\n    \"DEK-Info: AES-128-CBC,\",\n    \"DEK-Info: AES-256-CBC,\" \n};\n\n/**\n * Take a base64 blob of data and decrypt it (using AES) into its \n * proper ASN.1 form.\n */\nstatic int ICACHE_FLASH_ATTR pem_decrypt(const char *where, const char *end,\n                        const char *password, SSLObjLoader *ssl_obj)\n{\n    int ret = -1;\n    int is_aes_256 = 0;\n    char *start = NULL;\n    uint8_t iv[IV_SIZE];\n    int i, pem_size;\n    MD5_CTX md5_ctx;\n    AES_CTX aes_ctx;\n    uint8_t key[32];        /* AES256 size */\n\n    if (password == NULL || os_strlen(password) == 0)\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"Error: Need a password for this PEM file\\n\"); //TTY_FLUSH();\n#endif\n        goto error;\n    }\n\n    if ((start = (char *)os_strstr((const char *)where, aes_str[0])))         /* AES128? */\n    {\n        start += os_strlen(aes_str[0]);\n    }\n    else if ((start = (char *)os_strstr((const char *)where, aes_str[1])))    /* AES256? */\n    {\n        is_aes_256 = 1;\n        start += os_strlen(aes_str[1]);\n    }\n    else \n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"Error: Unsupported password cipher\\n\"); //TTY_FLUSH();\n#endif\n        goto error;\n    }\n\n    /* convert from hex to binary - assumes uppercase hex */\n    for (i = 0; i < IV_SIZE; i++)\n    {\n        char c = *start++ - '0';\n        iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4;\n        c = *start++ - '0';\n        iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c);\n    }\n\n    while (*start == '\\r' || *start == '\\n')\n        start++;\n\n    /* turn base64 into binary */\n    pem_size = (int)(end-start);\n    if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0)\n        goto error;\n\n    /* work out the key */\n    MD5_Init(&md5_ctx);\n    MD5_Update(&md5_ctx, (const uint8_t *)password, os_strlen(password));\n    MD5_Update(&md5_ctx, iv, SALT_SIZE);\n    MD5_Final(key, &md5_ctx);\n\n    if (is_aes_256)\n    {\n        MD5_Init(&md5_ctx);\n        MD5_Update(&md5_ctx, key, MD5_SIZE);\n        MD5_Update(&md5_ctx, (const uint8_t *)password, os_strlen(password));\n        MD5_Update(&md5_ctx, iv, SALT_SIZE);\n        MD5_Final(&key[MD5_SIZE], &md5_ctx);\n    }\n\n    /* decrypt using the key/iv */\n    AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128);\n    AES_convert_key(&aes_ctx);\n    AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len);\n    ret = 0;\n\nerror:\n    return ret; \n}\n\n/**\n * Take a base64 blob of data and turn it into its proper ASN.1 form.\n */\nstatic int ICACHE_FLASH_ATTR new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, \n                    int remain, const char *password)\n{\n    int ret = SSL_ERROR_BAD_CERTIFICATE;\n    SSLObjLoader *ssl_obj = NULL;\n\n    while (remain > 0)\n    {\n        int i, pem_size, obj_type;\n        char *start = NULL, *end = NULL;\n\n        for (i = 0; i < NUM_PEM_TYPES; i++)\n        {\n            if ((start = (char *)os_strstr(where, begins[i])) &&\n                    (end = (char *)os_strstr(where, ends[i])))\n            {\n                remain -= (int)(end-where);\n                start += os_strlen(begins[i]);\n                pem_size = (int)(end-start);\n\n                ssl_obj = (SSLObjLoader *)os_zalloc(sizeof(SSLObjLoader));\n\n                /* 4/3 bigger than what we need but so what */\n                ssl_obj->buf = (uint8_t *)os_zalloc(pem_size);\n                ssl_obj->len = pem_size;\n\n                if (i == IS_RSA_PRIVATE_KEY && \n                            os_strstr(start, \"Proc-Type:\") && \n                            os_strstr(start, \"4,ENCRYPTED\"))\n                {\n                    /* check for encrypted PEM file */\n                    if (pem_decrypt(start, end, password, ssl_obj) < 0)\n                    {\n                        ret = SSL_ERROR_BAD_CERTIFICATE;\n                        goto error;\n                    }\n                }\n                else \n                {\n                    ssl_obj->len = pem_size;\n                    if (base64_decode(start, pem_size, \n                                ssl_obj->buf, &ssl_obj->len) != 0)\n                    {\n                        ret = SSL_ERROR_BAD_CERTIFICATE;\n                        goto error;\n                    }\n                }\n\n                switch (i)\n                {\n                    case IS_RSA_PRIVATE_KEY:\n                        obj_type = SSL_OBJ_RSA_KEY;\n                        break;\n\n                    case IS_ENCRYPTED_PRIVATE_KEY:\n                    case IS_PRIVATE_KEY:\n                        obj_type = SSL_OBJ_PKCS8;\n                        break;\n\n                    case IS_CERTIFICATE:\n                        obj_type = is_cacert ?\n                                        SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT;\n                        break;\n\n                    default:\n                        ret = SSL_ERROR_BAD_CERTIFICATE;\n                        goto error;\n                }\n\n                /* In a format we can now understand - so process it */\n                if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password)))\n                    goto error;\n\n                end += os_strlen(ends[i]);\n                remain -= os_strlen(ends[i]);\n                while (remain > 0 && (*end == '\\r' || *end == '\\n'))\n                {\n                    end++;\n                    remain--;\n                }\n\n                where = end;\n                break;\n            }\n        }\n\n        ssl_obj_free(ssl_obj);\n        ssl_obj = NULL;\n        if (start == NULL)\n           break;\n    }\nerror:\n    ssl_obj_free(ssl_obj);\n    return ret;\n}\n\n/*\n * Load a file into memory that is in ASCII PEM format.\n */\nstatic int ICACHE_FLASH_ATTR ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, \n                        SSLObjLoader *ssl_obj, const char *password)\n{\n    char *start;\n\n    /* add a null terminator */\n    ssl_obj->len++;\n    ssl_obj->buf = (uint8_t *)os_realloc(ssl_obj->buf, ssl_obj->len);\n    ssl_obj->buf[ssl_obj->len-1] = 0;\n    start = (char *)ssl_obj->buf;\n    return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT,\n                                start, ssl_obj->len, password);\n}\n#endif /* CONFIG_SSL_HAS_PEM */\n\n/**\n * Load the key/certificates in memory depending on compile-time and user\n * options. \n */\nint ICACHE_FLASH_ATTR load_key_certs(SSL_CTX *ssl_ctx)\n{\n    int ret = SSL_OK;\n    uint32_t options = ssl_ctx->options;\n#ifdef CONFIG_SSL_GENERATE_X509_CERT \n    uint8_t *cert_data = NULL;\n    int cert_size;\n    static const char *dn[] = \n    {\n        CONFIG_SSL_X509_COMMON_NAME,\n        CONFIG_SSL_X509_ORGANIZATION_NAME,\n        CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME\n    };\n#endif\n\n    /* do the private key first */\n    if (os_strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0)\n    {\n        if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, \n                                CONFIG_SSL_PRIVATE_KEY_LOCATION,\n                                CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0)\n            goto error;\n    }\n    else if (!(options & SSL_NO_DEFAULT_KEY))\n    {\n#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)\n //       static const    /* saves a few more bytes */\n//#include \"private_key.h\"\n\t\t\n\t\textern unsigned int default_private_key_len;\n\t\textern unsigned char default_private_key[];\n        ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key,\n                default_private_key_len, NULL); \n#endif\n    }\n\n    /* now load the certificate */\n#ifdef CONFIG_SSL_GENERATE_X509_CERT \n    if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0)\n    {\n        ret = cert_size;\n        goto error;\n    }\n\n    ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL);\n    os_free(cert_data);\n#else\n    if (os_strlen(CONFIG_SSL_X509_CERT_LOCATION))\n    {\n        if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, \n                                CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0)\n            goto error;\n    }\n    else if (!(options & SSL_NO_DEFAULT_KEY))\n    {\n#if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)\n//        static const    /* saves a few bytes and RAM */\n//#include \"cert.h\"\n\t\textern unsigned char default_certificate[];\n\t\textern unsigned int default_certificate_len;\n        ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, \n                    default_certificate, default_certificate_len, NULL);\n#endif\n    }\n#endif\n\nerror:\n#ifdef CONFIG_SSL_FULL_MODE\n    if (ret)\n    {\n        ssl_printf(\"Error: Certificate or key not loaded\\n\"); //TTY_FLUSH();\n    }\n#endif\n\n    return ret;\n\n}\n"
  },
  {
    "path": "app/ssl/ssl/ssl_openssl.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n * Enable a subset of openssl compatible functions. We don't aim to be 100%\n * compatible - just to be able to do basic ports etc.\n *\n * Only really tested on mini_httpd, so I'm not too sure how extensive this\n * port is.\n */\n\n#include \"ssl/ssl_config.h\"\n\n#ifdef CONFIG_OPENSSL_COMPATIBLE\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_ssl.h\"\n\n#define OPENSSL_CTX_ATTR  ((OPENSSL_CTX *)ssl_ctx->bonus_attr)\n\nstatic char *key_password = NULL;\n\nvoid *SSLv23_server_method(void) { return NULL; }\nvoid *SSLv3_server_method(void) { return NULL; }\nvoid *TLSv1_server_method(void) { return NULL; }\nvoid *SSLv23_client_method(void) { return NULL; }\nvoid *SSLv3_client_method(void) { return NULL; }\nvoid *TLSv1_client_method(void) { return NULL; }\n\ntypedef void * (*ssl_func_type_t)(void);\ntypedef void * (*bio_func_type_t)(void);\n\ntypedef struct\n{\n    ssl_func_type_t ssl_func_type;\n} OPENSSL_CTX;\n\nSSL_CTX *ICACHE_FLASH_ATTR SSL_CTX_new(ssl_func_type_t meth)\n{\n    SSL_CTX *ssl_ctx = ssl_ctx_new(0, 5);\n    ssl_ctx->bonus_attr = os_malloc(sizeof(OPENSSL_CTX));\n    OPENSSL_CTX_ATTR->ssl_func_type = meth;\n    return ssl_ctx;\n}\n\nvoid ICACHE_FLASH_ATTR SSL_CTX_free(SSL_CTX *ssl_ctx)\n{\n    free(ssl_ctx->bonus_attr);\n    ssl_ctx_free(ssl_ctx);\n}\n\nSSL *ICACHE_FLASH_ATTR SSL_new(SSL_CTX *ssl_ctx)\n{\n    SSL *ssl;\n    ssl_func_type_t ssl_func_type;\n\n    ssl = ssl_new(ssl_ctx, -1);        /* fd is set later */\n    ssl_func_type = OPENSSL_CTX_ATTR->ssl_func_type;\n\n#ifdef CONFIG_SSL_ENABLE_CLIENT\n    if (ssl_func_type == SSLv23_client_method ||\n        ssl_func_type == SSLv3_client_method ||\n        ssl_func_type == TLSv1_client_method)\n    {\n        SET_SSL_FLAG(SSL_IS_CLIENT);\n    }\n    else\n#endif\n    {\n        ssl->next_state = HS_CLIENT_HELLO;\n    }\n\n    return ssl;\n}\n\nint ICACHE_FLASH_ATTR SSL_set_fd(SSL *s, int fd)\n{\n    s->client_fd = fd;\n    return 1;   /* always succeeds */\n}\n\nint ICACHE_FLASH_ATTR SSL_accept(SSL *ssl)\n{\n    while (ssl_read(ssl, NULL) == SSL_OK)\n    {\n        if (ssl->next_state == HS_CLIENT_HELLO)\n            return 1;   /* we're done */\n    }\n\n    return -1;\n}\n\n#ifdef CONFIG_SSL_ENABLE_CLIENT\nint ICACHE_FLASH_ATTR SSL_connect(SSL *ssl)\n{\n    return do_client_connect(ssl) == SSL_OK ? 1 : -1;\n}\n#endif\n\nvoid ICACHE_FLASH_ATTR SSL_free(SSL *ssl)\n{\n    ssl_free(ssl);\n}\n\nint ICACHE_FLASH_ATTR SSL_read(SSL *ssl, void *buf, int num)\n{\n    uint8_t *read_buf;\n    int ret;\n\n    while ((ret = ssl_read(ssl, &read_buf)) == SSL_OK);\n\n    if (ret > SSL_OK)\n    {\n        os_memcpy(buf, read_buf, ret > num ? num : ret);\n    }\n\n    return ret;\n}\n\nint ICACHE_FLASH_ATTR SSL_write(SSL *ssl, const void *buf, int num)\n{\n    return ssl_write(ssl, buf, num);\n}\n\nint ICACHE_FLASH_ATTR SSL_CTX_use_certificate_file(SSL_CTX *ssl_ctx, const char *file, int type)\n{\n    return (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);\n}\n\nint ICACHE_FLASH_ATTR SSL_CTX_use_PrivateKey_file(SSL_CTX *ssl_ctx, const char *file, int type)\n{\n    return (ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, file, key_password) == SSL_OK);\n}\n\nint ICACHE_FLASH_ATTR SSL_CTX_use_certificate_ASN1(SSL_CTX *ssl_ctx, int len, const uint8_t *d)\n{\n    return (ssl_obj_memory_load(ssl_ctx, \n                        SSL_OBJ_X509_CERT, d, len, NULL) == SSL_OK);\n}\n\nint ICACHE_FLASH_ATTR SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,\n        unsigned int sid_ctx_len)\n{\n    return 1;\n}\n\nint ICACHE_FLASH_ATTR SSL_CTX_set_default_verify_paths(SSL_CTX *ctx)\n{\n    return 1;\n}\n\nint ICACHE_FLASH_ATTR SSL_CTX_use_certificate_chain_file(SSL_CTX *ssl_ctx, const char *file)\n{\n    return (ssl_obj_load(ssl_ctx, \n                        SSL_OBJ_X509_CERT, file, NULL) == SSL_OK);\n}\n\nint ICACHE_FLASH_ATTR SSL_shutdown(SSL *ssl)\n{\n    return 1;\n}\n\n/*** get/set session ***/\nSSL_SESSION *ICACHE_FLASH_ATTR SSL_get1_session(SSL *ssl)\n{\n    return (SSL_SESSION *)ssl_get_session_id(ssl); /* note: wrong cast */\n}\n\nint ICACHE_FLASH_ATTR SSL_set_session(SSL *ssl, SSL_SESSION *session)\n{\n    os_memcpy(ssl->session_id, (uint8_t *)session, SSL_SESSION_ID_SIZE);\n    return 1;\n}\n\nvoid ICACHE_FLASH_ATTR SSL_SESSION_free(SSL_SESSION *session) { }\n/*** end get/set session ***/\n\nlong ICACHE_FLASH_ATTR SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)\n{\n    return 0;\n}\n\nvoid ICACHE_FLASH_ATTR SSL_CTX_set_verify(SSL_CTX *ctx, int mode,\n        int (*verify_callback)(int, void *)) { }\n\nvoid ICACHE_FLASH_ATTR SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { }\n\nint ICACHE_FLASH_ATTR SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,\n        const char *CApath)\n{\n    return 1;\n}\n\nvoid *ICACHE_FLASH_ATTR SSL_load_client_CA_file(const char *file)\n{\n    return (void *)file;\n}\n\nvoid ICACHE_FLASH_ATTR SSL_CTX_set_client_CA_list(SSL_CTX *ssl_ctx, void *file)\n{\n    ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, (const char *)file, NULL);\n}\n\nvoid ICACHE_FLASH_ATTR SSLv23_method(void) { }\n\nvoid ICACHE_FLASH_ATTR SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, void *cb) { }\n\nvoid ICACHE_FLASH_ATTR SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u)\n{\n    key_password = (char *)u;\n}\n\nint ICACHE_FLASH_ATTR SSL_peek(SSL *ssl, void *buf, int num)\n{\n    os_memcpy(buf, ssl->bm_data, num);\n    return num;\n}\n\nvoid ICACHE_FLASH_ATTR SSL_set_bio(SSL *ssl, void *rbio, void *wbio) { }\n\nlong ICACHE_FLASH_ATTR SSL_get_verify_result(const SSL *ssl)\n{\n    return ssl_handshake_status(ssl);\n}\n\nint ICACHE_FLASH_ATTR SSL_state(SSL *ssl)\n{\n    return 0x03; // ok state\n}\n\n/** end of could do better list */\n\nvoid *ICACHE_FLASH_ATTR SSL_get_peer_certificate(const SSL *ssl)\n{\n    return &ssl->ssl_ctx->certs[0];\n}\n\nint ICACHE_FLASH_ATTR SSL_clear(SSL *ssl)\n{\n    return 1;\n}\n\n\nint ICACHE_FLASH_ATTR SSL_CTX_check_private_key(const SSL_CTX *ctx)\n{\n    return 1;\n}\n\nint ICACHE_FLASH_ATTR SSL_CTX_set_cipher_list(SSL *s, const char *str)\n{\n    return 1;\n}\n\nint ICACHE_FLASH_ATTR SSL_get_error(const SSL *ssl, int ret)\n{\n    ssl_display_error(ret);\n    return 0;   /* TODO: return proper return code */\n}\n\nvoid ICACHE_FLASH_ATTR SSL_CTX_set_options(SSL_CTX *ssl_ctx, int option) {}\nint ICACHE_FLASH_ATTR SSL_library_init(void ) { return 1; }\nvoid ICACHE_FLASH_ATTR SSL_load_error_strings(void ) {}\nvoid ICACHE_FLASH_ATTR ERR_print_errors_fp(FILE *fp) {}\n\n#ifndef CONFIG_SSL_SKELETON_MODE\nlong ICACHE_FLASH_ATTR SSL_CTX_get_timeout(const SSL_CTX *ssl_ctx) { \n                            return CONFIG_SSL_EXPIRY_TIME*3600; }\nlong ICACHE_FLASH_ATTR SSL_CTX_set_timeout(SSL_CTX *ssl_ctx, long t) { \n                            return SSL_CTX_get_timeout(ssl_ctx); }\n#endif\nvoid ICACHE_FLASH_ATTR BIO_printf(FILE *f, const char *format, ...)\n{\n    va_list(ap);\n    va_start(ap, format);\n    vfprintf(f, format, ap);\n    va_end(ap);\n}\n\nvoid* ICACHE_FLASH_ATTR BIO_s_null(void) { return NULL; }\nFILE *ICACHE_FLASH_ATTR BIO_new(bio_func_type_t func)\n{\n    if (func == BIO_s_null)\n        return fopen(\"/dev/null\", \"r\");\n    else\n        return NULL;\n}\n\nFILE *ICACHE_FLASH_ATTR BIO_new_fp(FILE *stream, int close_flag) { return stream; }\nint ICACHE_FLASH_ATTR BIO_free(FILE *a) { if (a != stdout && a != stderr) fclose(a); return 1; }\n\n\n\n#endif\n"
  },
  {
    "path": "app/ssl/ssl/ssl_os_port.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @file os_port.c\n *\n * OS specific functions.\n */\n//#include <time.h>\n//#include <stdlib.h>\n//#include <errno.h>\n//#include <stdarg.h>\n#include \"ssl/ssl_os_port.h\"\n\n#ifdef WIN32\n/**\n * gettimeofday() not in Win32 \n */\nEXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)\n{       \n#if defined(_WIN32_WCE)\n    t->tv_sec = time(NULL);\n    t->tv_usec = 0;                         /* 1sec precision only */ \n#else\n    struct _timeb timebuffer;\n    _ftime(&timebuffer);\n    t->tv_sec = (long)timebuffer.time;\n    t->tv_usec = 1000 * timebuffer.millitm; /* 1ms precision */\n#endif\n}\n\n/**\n * strcasecmp() not in Win32\n */\nEXP_FUNC int STDCALL strcasecmp(const char *s1, const char *s2)\n{\n    while (tolower(*s1) == tolower(*s2++))\n    {\n        if (*s1++ == '\\0')\n        {\n            return 0;\n        }\n    }\n\n    return *(unsigned char *)s1 - *(unsigned char *)(s2 - 1);\n}\n\n\nEXP_FUNC int STDCALL getdomainname(char *buf, int buf_size)\n{\n    HKEY hKey;\n    unsigned long datatype;\n    unsigned long bufferlength = buf_size;\n\n    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,\n            TEXT(\"SYSTEM\\\\CurrentControlSet\\\\Services\\\\Tcpip\\\\Parameters\"),\n                        0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)\n        return -1;\n\n    RegQueryValueEx(hKey, \"Domain\", NULL, &datatype, buf, &bufferlength);\n    RegCloseKey(hKey);\n    return 0; \n}\n#endif\n\n#if 0\n#undef malloc\n#undef realloc\n#undef calloc\n\nstatic const char * out_of_mem_str = \"out of memory\";\nstatic const char * file_open_str = \"Could not open file \\\"%s\\\"\";\n\n/* \n * Some functions that call display some error trace and then call abort().\n * This just makes life much easier on embedded systems, since we're \n * suffering major trauma...\n */\nEXP_FUNC void * STDCALL ax_malloc(size_t s)\n{\n    void *x;\n\n    if ((x = malloc(s)) == NULL)\n        exit_now(out_of_mem_str);\n\n    return x;\n}\n\nEXP_FUNC void * STDCALL ax_realloc(void *y, size_t s)\n{\n    void *x;\n\n    if ((x = realloc(y, s)) == NULL)\n        exit_now(out_of_mem_str);\n\n    return x;\n}\n\nEXP_FUNC void * STDCALL ax_calloc(size_t n, size_t s)\n{\n    void *x;\n\n    if ((x = calloc(n, s)) == NULL)\n        exit_now(out_of_mem_str);\n\n    return x;\n}\n\nEXP_FUNC int STDCALL ax_open(const char *pathname, int flags)\n{\n    int x;\n\n    if ((x = open(pathname, flags)) < 0)\n        exit_now(file_open_str, pathname);\n\n    return x;\n}\n\n/**\n * This is a call which will deliberately exit an application, but will\n * display some information before dying.\n */\nvoid exit_now(const char *format, ...)\n{\n    va_list argp;\n\n    va_start(argp, format);\n    vfprintf(stderr, format, argp);\n    va_end(argp);\n    abort();\n}\n\n\n/**\n * gettimeofday() not in Win32 \n */\nEXP_FUNC void STDCALL gettimeofday(struct timeval* t, void* timezone)\n{       \n#if defined(_WIN32_WCE)\n    t->tv_sec = time(NULL);\n    t->tv_usec = 0;                         /* 1sec precision only */ \n#else\n    /* wujg : pass compile first */\n    t->tv_sec = 0;\n    t->tv_usec = 0; /* 1ms precision */\n#endif\n}\n#endif\n\n"
  },
  {
    "path": "app/ssl/ssl/ssl_p12.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * Process PKCS#8/PKCS#12 keys.\n *\n * The decoding of a PKCS#12 key is fairly specific - this code was tested on a\n * key generated with:\n *\n * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem\n * -keypbe PBE-SHA1-RC4-128 -certpbe PBE-SHA1-RC4-128 \n * -name \"p12_withoutCA\" -out axTLS.withoutCA.p12 -password pass:abcd\n *\n * or with a certificate chain:\n *\n * openssl pkcs12 -export -in axTLS.x509_1024.pem -inkey axTLS.key_1024.pem\n * -certfile axTLS.ca_x509.pem -keypbe PBE-SHA1-RC4-128 -certpbe\n * PBE-SHA1-RC4-128 -name \"p12_withCA\" -out axTLS.withCA.p12 -password pass:abcd\n *\n * Note that the PBE has to be specified with PBE-SHA1-RC4-128. The\n * private/public keys/certs have to use RSA encryption. Both the integrity\n * and privacy passwords are the same.\n *\n * The PKCS#8 files were generated with something like:\n *\n * PEM format:\n * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -v1\n * PBE-SHA1-RC4-128 -out axTLS.encrypted_pem.p8\n *\n * DER format:\n * openssl pkcs8 -in axTLS.key_512.pem -passout pass:abcd -topk8 -outform DER\n * -v1 PBE-SHA1-RC4-128 -out axTLS.encrypted.p8\n */\n\n//#include <stdlib.h>\n//#include <string.h>\n//#include <stdio.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_ssl.h\"\n\n/* all commented out if not used */\n#ifdef CONFIG_SSL_USE_PKCS12\n\n#define BLOCK_SIZE          64\n#define PKCS12_KEY_ID       1\n#define PKCS12_IV_ID        2\n#define PKCS12_MAC_ID       3\n\nstatic char *make_uni_pass(const char *password, int *uni_pass_len);\nstatic int p8_decrypt(const char *uni_pass, int uni_pass_len, \n                        const uint8_t *salt, int iter, \n                        uint8_t *priv_key, int priv_key_len, int id);\nstatic int p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key);\nstatic int get_pbe_params(uint8_t *buf, int *offset, \n        const uint8_t **salt, int *iterations);\n\n/*\n * Take a raw pkcs8 block and then decrypt it and turn it into a normal key.\n */\nint ICACHE_FLASH_ATTR pkcs8_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)\n{\n    uint8_t *buf = ssl_obj->buf;\n    int len, offset = 0;\n    int iterations;\n    int ret = SSL_NOT_OK;\n    uint8_t *version = NULL;\n    const uint8_t *salt;\n    uint8_t *priv_key;\n    int uni_pass_len;\n    char *uni_pass = make_uni_pass(password, &uni_pass_len);\n\n    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"Error: Invalid p8 ASN.1 file\\n\");\n#endif\n        goto error;\n    }\n\n    /* unencrypted key? */\n    if (asn1_get_int(buf, &offset, &version) > 0 && *version == 0)\n    {\n        ret = p8_add_key(ssl_ctx, buf);\n        goto error;\n    }\n\n    if (get_pbe_params(buf, &offset, &salt, &iterations) < 0)\n        goto error;\n\n    if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)\n        goto error;\n\n    priv_key = &buf[offset];\n\n    p8_decrypt(uni_pass, uni_pass_len, salt, \n                        iterations, priv_key, len, PKCS12_KEY_ID);\n    ret = p8_add_key(ssl_ctx, priv_key);\n\nerror:\n    os_free(version);\n    os_free(uni_pass);\n    return ret;\n}\n\n/*\n * Take the unencrypted pkcs8 and turn it into a private key \n */\nstatic int ICACHE_FLASH_ATTR p8_add_key(SSL_CTX *ssl_ctx, uint8_t *priv_key)\n{\n    uint8_t *buf = priv_key;\n    int len, offset = 0;\n    int ret = SSL_NOT_OK;\n\n    /* Skip the preamble and go straight to the private key.\n       We only support rsaEncryption (1.2.840.113549.1.1.1)  */\n    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||\n            asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)\n        goto error;\n\n    ret = asn1_get_private_key(&buf[offset], len, &ssl_ctx->rsa_ctx);\n\nerror:\n    return ret;\n}\n\n/*\n * Create the unicode password \n */\nstatic char * ICACHE_FLASH_ATTR make_uni_pass(const char *password, int *uni_pass_len)\n{\n    int pass_len = 0, i;\n    char *uni_pass;\n\n    if (password == NULL)\n    {\n        password = \"\";\n    }\n\n    uni_pass = (char *)os_malloc((os_strlen(password)+1)*2);\n\n    /* modify the password into a unicode version */\n    for (i = 0; i < (int)os_strlen(password); i++)\n    {\n        uni_pass[pass_len++] = 0;\n        uni_pass[pass_len++] = password[i];\n    }\n\n    uni_pass[pass_len++] = 0;       /* null terminate */\n    uni_pass[pass_len++] = 0;\n    *uni_pass_len = pass_len;\n    return uni_pass;\n}\n\n/*\n * Decrypt a pkcs8 block.\n */\nstatic int ICACHE_FLASH_ATTR p8_decrypt(const char *uni_pass, int uni_pass_len,\n                        const uint8_t *salt, int iter, \n                        uint8_t *priv_key, int priv_key_len, int id)\n{\n    uint8_t p[BLOCK_SIZE*2];\n    uint8_t d[BLOCK_SIZE];\n    uint8_t Ai[SHA1_SIZE];\n    SHA1_CTX sha_ctx;\n    RC4_CTX rc4_ctx;\n    int i;\n\n    for (i = 0; i < BLOCK_SIZE; i++)\n    {\n        p[i] = salt[i % SALT_SIZE];\n        p[BLOCK_SIZE+i] = uni_pass[i % uni_pass_len];\n        d[i] = id;\n    }\n\n    /* get the key - no IV since we are using RC4 */\n    SHA1_Init(&sha_ctx);\n    SHA1_Update(&sha_ctx, d, sizeof(d));\n    SHA1_Update(&sha_ctx, p, sizeof(p));\n    SHA1_Final(Ai, &sha_ctx);\n\n    for (i = 1; i < iter; i++)\n    {\n        SHA1_Init(&sha_ctx);\n        SHA1_Update(&sha_ctx, Ai, SHA1_SIZE);\n        SHA1_Final(Ai, &sha_ctx);\n    }\n\n    /* do the decryption */\n    if (id == PKCS12_KEY_ID)\n    {\n        RC4_setup(&rc4_ctx, Ai, 16);\n        RC4_crypt(&rc4_ctx, priv_key, priv_key, priv_key_len);\n    }\n    else  /* MAC */\n        os_memcpy(priv_key, Ai, SHA1_SIZE);\n\n    return 0;\n}\n\n/*\n * Take a raw pkcs12 block and the decrypt it and turn it into a certificate(s)\n * and keys.\n */\nint ICACHE_FLASH_ATTR pkcs12_decode(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password)\n{\n    uint8_t *buf = ssl_obj->buf;\n    int len, iterations, auth_safes_start, \n              auth_safes_end, auth_safes_len, key_offset, offset = 0;\n    int all_certs = 0;\n    uint8_t *version = NULL, *auth_safes = NULL, *cert, *orig_mac;\n    uint8_t key[SHA1_SIZE];\n    uint8_t mac[SHA1_SIZE];\n    const uint8_t *salt;\n    int uni_pass_len, ret = SSL_OK;\n    char *uni_pass = make_uni_pass(password, &uni_pass_len);\n    static const uint8_t pkcs_data[] = /* pkc7 data */\n        { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01 };\n    static const uint8_t pkcs_encrypted[] = /* pkc7 encrypted */\n        { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06 };\n    static const uint8_t pkcs8_key_bag[] = /* 1.2.840.113549.1.12.10.1.2 */\n        { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x0a, 0x01, 0x02 };\n\n    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0)\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"Error: Invalid p12 ASN.1 file\\n\");\n#endif\n        goto error;\n    }\n\n    if (asn1_get_int(buf, &offset, &version) < 0 || *version != 3)\n    {\n        ret = SSL_ERROR_INVALID_VERSION;\n        goto error;\n    }\n\n    /* remove all the boring pcks7 bits */\n    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 || \n                (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||\n                len != sizeof(pkcs_data) || \n                os_memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))\n        goto error;\n\n    offset += len;\n\n    if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0)\n        goto error;\n\n    /* work out the MAC start/end points (done on AuthSafes) */\n    auth_safes_start = offset;\n    auth_safes_end = offset;\n    if (asn1_skip_obj(buf, &auth_safes_end, ASN1_SEQUENCE) < 0)\n        goto error;\n\n    auth_safes_len = auth_safes_end - auth_safes_start;\n    auth_safes = os_malloc(auth_safes_len);\n\n    os_memcpy(auth_safes, &buf[auth_safes_start], auth_safes_len);\n\n    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||\n            (len != sizeof(pkcs_encrypted) || \n            os_memcmp(&buf[offset], pkcs_encrypted, sizeof(pkcs_encrypted))))\n        goto error;\n\n    offset += len;\n\n    if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            asn1_skip_obj(buf, &offset, ASN1_INTEGER) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||\n            len != sizeof(pkcs_data) || \n            os_memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))\n        goto error;\n\n    offset += len;\n\n    /* work out the salt for the certificate */\n    if (get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||\n            (len = asn1_next_obj(buf, &offset, ASN1_IMPLICIT_TAG)) < 0)\n        goto error;\n\n    /* decrypt the certificate */\n    cert = &buf[offset];\n    if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, \n                            len, PKCS12_KEY_ID)) < 0)\n        goto error;\n\n    offset += len;\n\n    /* load the certificate */\n    key_offset = 0;\n    all_certs = asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE);\n\n    /* keep going until all certs are loaded */\n    while (key_offset < all_certs)\n    {\n        int cert_offset = key_offset;\n\n        if (asn1_skip_obj(cert, &cert_offset, ASN1_SEQUENCE) < 0 ||\n                asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||\n                asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||\n                asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||\n                asn1_next_obj(cert, &key_offset, ASN1_SEQUENCE) < 0 ||\n                asn1_skip_obj(cert, &key_offset, ASN1_OID) < 0 ||\n                asn1_next_obj(cert, &key_offset, ASN1_EXPLICIT_TAG) < 0 ||\n                (len = asn1_next_obj(cert, &key_offset, ASN1_OCTET_STRING)) < 0)\n            goto error;\n\n        if ((ret = add_cert(ssl_ctx, &cert[key_offset], len)) < 0)\n            goto error;\n\n        key_offset = cert_offset;\n    }\n\n    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||\n            len != sizeof(pkcs_data) || \n            os_memcmp(&buf[offset], pkcs_data, sizeof(pkcs_data)))\n        goto error;\n\n    offset += len;\n\n    if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_OCTET_STRING) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            (len = asn1_next_obj(buf, &offset, ASN1_OID)) < 0 ||\n            (len != sizeof(pkcs8_key_bag)) || \n            os_memcmp(&buf[offset], pkcs8_key_bag, sizeof(pkcs8_key_bag)))\n        goto error;\n\n    offset += len;\n\n    /* work out the salt for the private key */\n    if (asn1_next_obj(buf, &offset, ASN1_EXPLICIT_TAG) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            get_pbe_params(buf, &offset, &salt, &iterations) < 0 ||\n            (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0)\n        goto error;\n\n    /* decrypt the private key */\n    cert = &buf[offset];\n    if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, cert, \n                            len, PKCS12_KEY_ID)) < 0)\n        goto error;\n\n    offset += len;\n\n    /* load the private key */\n    if ((ret = p8_add_key(ssl_ctx, cert)) < 0)\n        goto error;\n\n    /* miss out on friendly name, local key id etc */\n    if (asn1_skip_obj(buf, &offset, ASN1_SET) < 0)\n        goto error;\n\n    /* work out the MAC */\n    if (asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            asn1_next_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            asn1_skip_obj(buf, &offset, ASN1_SEQUENCE) < 0 ||\n            (len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 ||\n            len != SHA1_SIZE)\n        goto error;\n\n    orig_mac = &buf[offset];\n    offset += len;\n\n    /* get the salt */\n    if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8)\n        goto error;\n\n    salt = &buf[offset];\n\n    /* work out what the mac should be */\n    if ((ret = p8_decrypt(uni_pass, uni_pass_len, salt, iterations, \n                            key, SHA1_SIZE, PKCS12_MAC_ID)) < 0)\n        goto error;\n\n    ssl_hmac_sha1(auth_safes, auth_safes_len, key, SHA1_SIZE, mac);\n\n    if (os_memcmp(mac, orig_mac, SHA1_SIZE))\n    {\n        ret = SSL_ERROR_INVALID_HMAC;                  \n        goto error;\n    }\n\nerror:\n    os_free(version);\n    os_free(uni_pass);\n    os_free(auth_safes);\n    return ret;\n}\n\n/*\n * Retrieve the salt/iteration details from a PBE block.\n */\nstatic int ICACHE_FLASH_ATTR get_pbe_params(uint8_t *buf, int *offset, \n        const uint8_t **salt, int *iterations)\n{\n    static const uint8_t pbeSH1RC4[] = /* pbeWithSHAAnd128BitRC4  */\n            { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x01 };\n\n    int i, len;\n    uint8_t *iter = NULL;\n    int error_code = SSL_ERROR_NOT_SUPPORTED;\n\n    /* Get the PBE type */\n    if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||\n            (len = asn1_next_obj(buf, offset, ASN1_OID)) < 0)\n        goto error;\n\n    /* we expect pbeWithSHAAnd128BitRC4 (1.2.840.113549.1.12.1.1) \n       which is the only algorithm we support */\n    if (len != sizeof(pbeSH1RC4) || \n                    os_memcmp(&buf[*offset], pbeSH1RC4, sizeof(pbeSH1RC4)))\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"Error: pkcs8/pkcs12 must use \\\"PBE-SHA1-RC4-128\\\"\\n\");\n#endif\n        goto error;\n    }\n\n    *offset += len;\n\n    if (asn1_next_obj(buf, offset, ASN1_SEQUENCE) < 0 ||\n            (len = asn1_next_obj(buf, offset, ASN1_OCTET_STRING)) < 0 || \n            len != 8)\n        goto error;\n\n    *salt = &buf[*offset];\n    *offset += len;\n\n    if ((len = asn1_get_int(buf, offset, &iter)) < 0)\n        goto error;\n\n    *iterations = 0;\n    for (i = 0; i < len; i++)\n    {\n        (*iterations) <<= 8;\n        (*iterations) += iter[i];\n    }\n\n    os_free(iter);\n    error_code = SSL_OK;       /* got here - we are ok */\n\nerror:\n    return error_code;\n}\n\n#endif\n"
  },
  {
    "path": "app/ssl/ssl/ssl_tls1.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * Common ssl/tlsv1 code to both the client and server implementations.\n */\n\n//#include <string.h>\n//#include <stdlib.h>\n//#include <stdio.h>\n//#include <stdarg.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_ssl.h\"\n#include \"lwip/tcp.h\"\n#include \"ssl/app/espconn_ssl.h\"\n\nextern struct pbuf* psslpbuf;\n/* The session expiry time */\n#define SSL_EXPIRY_TIME     (CONFIG_SSL_EXPIRY_TIME*3600)\n\nstatic const uint8_t g_hello_request[] = { HS_HELLO_REQUEST, 0, 0, 0 };\nstatic const uint8_t g_chg_cipher_spec_pkt[] = { 1 };\nstatic const char * server_finished = \"server finished\";\nstatic const char * client_finished = \"client finished\";\n\nstatic int do_handshake(SSL *ssl, uint8_t *buf, int read_len);\nstatic int set_key_block(SSL *ssl, int is_write);\nstatic int verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len);\nstatic void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt);\nstatic err_t send_raw_packet(SSL *ssl, uint8_t protocol);\n\n/**\n * The server will pick the cipher based on the order that the order that the\n * ciphers are listed. This order is defined at compile time.\n */\n#ifdef CONFIG_SSL_SKELETON_MODE\nconst uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = \n{ SSL_RC4_128_SHA };\n#else\nstatic void session_free(SSL_SESSION *ssl_sessions[], int sess_index);\n\nconst uint8_t ssl_prot_prefs[NUM_PROTOCOLS] = \n#ifdef CONFIG_SSL_PROT_LOW                  /* low security, fast speed */\n{ SSL_RC4_128_SHA, SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_MD5 };\n#elif CONFIG_SSL_PROT_MEDIUM                /* medium security, medium speed */\n{ SSL_AES128_SHA, SSL_AES256_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 };    \n#else /* CONFIG_SSL_PROT_HIGH */            /* high security, low speed */\n{ SSL_AES256_SHA, SSL_AES128_SHA, SSL_RC4_128_SHA, SSL_RC4_128_MD5 };\n#endif\n#endif /* CONFIG_SSL_SKELETON_MODE */\n\n/**\n * The cipher map containing all the essentials for each cipher.\n */\n#ifdef CONFIG_SSL_SKELETON_MODE\nstatic const cipher_info_t cipher_info[NUM_PROTOCOLS] = \n{\n    {   /* RC4-SHA */\n        SSL_RC4_128_SHA,                /* RC4-SHA */\n        16,                             /* key size */\n        0,                              /* iv size */ \n        2*(SHA1_SIZE+16),               /* key block size */\n        0,                              /* no padding */\n        SHA1_SIZE,                      /* digest size */\n        ssl_hmac_sha1,                      /* hmac algorithm */\n        (crypt_func)RC4_crypt,          /* encrypt */\n        (crypt_func)RC4_crypt           /* decrypt */\n    },\n};\n#else\nstatic const cipher_info_t cipher_info[NUM_PROTOCOLS] = \n{\n    {   /* AES128-SHA */\n        SSL_AES128_SHA,                 /* AES128-SHA */\n        16,                             /* key size */\n        16,                             /* iv size */ \n        2*(SHA1_SIZE+16+16),            /* key block size */\n        16,                             /* block padding size */\n        SHA1_SIZE,                      /* digest size */\n        ssl_hmac_sha1,                      /* hmac algorithm */\n        (crypt_func)AES_cbc_encrypt,    /* encrypt */\n        (crypt_func)AES_cbc_decrypt     /* decrypt */\n    },\n    {   /* AES256-SHA */\n        SSL_AES256_SHA,                 /* AES256-SHA */\n        32,                             /* key size */\n        16,                             /* iv size */ \n        2*(SHA1_SIZE+32+16),            /* key block size */\n        16,                             /* block padding size */\n        SHA1_SIZE,                      /* digest size */\n        ssl_hmac_sha1,                      /* hmac algorithm */\n        (crypt_func)AES_cbc_encrypt,    /* encrypt */\n        (crypt_func)AES_cbc_decrypt     /* decrypt */\n    },       \n    {   /* RC4-SHA */\n        SSL_RC4_128_SHA,                /* RC4-SHA */\n        16,                             /* key size */\n        0,                              /* iv size */ \n        2*(SHA1_SIZE+16),               /* key block size */\n        0,                              /* no padding */\n        SHA1_SIZE,                      /* digest size */\n        ssl_hmac_sha1,                      /* hmac algorithm */\n        (crypt_func)RC4_crypt,          /* encrypt */\n        (crypt_func)RC4_crypt           /* decrypt */\n    },\n    /*\n     * This protocol is from SSLv2 days and is unlikely to be used - but was\n     * useful for testing different possible digest algorithms.\n     */\n    {   /* RC4-MD5 */\n        SSL_RC4_128_MD5,                /* RC4-MD5 */\n        16,                             /* key size */\n        0,                              /* iv size */ \n        2*(MD5_SIZE+16),                /* key block size */\n        0,                              /* no padding */\n        MD5_SIZE,                       /* digest size */\n        ssl_hmac_md5,                       /* hmac algorithm */\n        (crypt_func)RC4_crypt,          /* encrypt */\n        (crypt_func)RC4_crypt           /* decrypt */\n    },\n};\n#endif\n\nstatic void prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len,\n        uint8_t *out, int olen);\nstatic const cipher_info_t *get_cipher_info(uint8_t cipher);\nstatic void increment_read_sequence(SSL *ssl);\nstatic void increment_write_sequence(SSL *ssl);\nstatic void add_hmac_digest(SSL *ssl, int snd, uint8_t *hmac_header,\n        const uint8_t *buf, int buf_len, uint8_t *hmac_buf);\n\n/* win32 VC6.0 doesn't have variadic macros */\n#if defined(WIN32) && !defined(CONFIG_SSL_FULL_MODE)\nvoid DISPLAY_BYTES(SSL *ssl, const char *format, \n        const uint8_t *data, int size, ...) {}\n#endif\n\n/**\n * Establish a new client/server context.\n */\nEXP_FUNC SSL_CTX *STDCALL ICACHE_FLASH_ATTR ssl_ctx_new(uint32_t options, int num_sessions)\n{\n    SSL_CTX *ssl_ctx = (SSL_CTX *)os_zalloc(sizeof (SSL_CTX));\n    ssl_ctx->options = options;\n    RNG_initialize();\n\n    if (load_key_certs(ssl_ctx) < 0)\n    {\n        os_free(ssl_ctx);  /* can't load our key/certificate pair, so die */\n        return NULL;\n    }\n\n#ifndef CONFIG_SSL_SKELETON_MODE\n    ssl_ctx->num_sessions = num_sessions;\n#endif\n\n    SSL_CTX_MUTEX_INIT(ssl_ctx->mutex);\n\n#ifndef CONFIG_SSL_SKELETON_MODE\n    if (num_sessions)\n    {\n        ssl_ctx->ssl_sessions = (SSL_SESSION **)\n                        os_zalloc(num_sessions*sizeof(SSL_SESSION *));\n    }\n#endif\n\n    return ssl_ctx;\n}\n\n/*\n * Remove a client/server context.\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR ssl_ctx_free(SSL_CTX *ssl_ctx)\n{\n    SSL *ssl;\n    int i;\n\n    if (ssl_ctx == NULL)\n        return;\n\n    ssl = ssl_ctx->head;\n\n    /* clear out all the ssl entries */\n    while (ssl)\n    {\n        SSL *next = ssl->next;\n        ssl_free(ssl);\n        ssl = next;\n    }\n\n#ifndef CONFIG_SSL_SKELETON_MODE\n    /* clear out all the sessions */\n    for (i = 0; i < ssl_ctx->num_sessions; i++)\n        session_free(ssl_ctx->ssl_sessions, i);\n\n    os_free(ssl_ctx->ssl_sessions);\n#endif\n\n    i = 0;\n    while (i < CONFIG_SSL_MAX_CERTS && ssl_ctx->certs[i].buf)\n    {\n        os_free(ssl_ctx->certs[i].buf);\n        ssl_ctx->certs[i++].buf = NULL;\n    }\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n    remove_ca_certs(ssl_ctx->ca_cert_ctx);\n#endif\n    ssl_ctx->chain_length = 0;\n    SSL_CTX_MUTEX_DESTROY(ssl_ctx->mutex);\n//\tssl_printf(\"%s %p\\n\", __func__,ssl_ctx->rsa_ctx);\n    RSA_free(ssl_ctx->rsa_ctx);\n    RNG_terminate();\n//\tssl_printf(\"%s %p\\n\", __func__,ssl_ctx);\n    os_free(ssl_ctx);\n}\n\n/*\n * Free any used resources used by this connection.\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR ssl_free(SSL *ssl)\n{\n    SSL_CTX *ssl_ctx;\n\n    if (ssl == NULL)        /* just ignore null pointers */\n        return;\n\n    /* only notify if we weren't notified first */\n    /* spec says we must notify when we are dying */\n    if (!IS_SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY))\n      send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);\n//\t\tssl_printf(\"%s %d\\n\", __func__, __LINE__);\t  \n\n    ssl_ctx = ssl->ssl_ctx;\n\n    SSL_CTX_LOCK(ssl_ctx->mutex);\n\n    /* adjust the server SSL list */\n    if (ssl->prev)\n        ssl->prev->next = ssl->next;\n    else\n        ssl_ctx->head = ssl->next;\n\n    if (ssl->next)\n        ssl->next->prev = ssl->prev;\n    else\n        ssl_ctx->tail = ssl->prev;\n\n    SSL_CTX_UNLOCK(ssl_ctx->mutex);\n\n    /* may already be free - but be sure */\n    os_free(ssl->encrypt_ctx);\n    os_free(ssl->decrypt_ctx);\n    disposable_free(ssl);\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n    x509_free(ssl->x509_ctx);\n#endif\n\n    os_free(ssl);\n}\n\n/*\n * Read the SSL connection and send any alerts for various errors.\n */\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_read(SSL *ssl, uint8_t **in_data)\n{\n    int ret = basic_read(ssl, in_data);\n\n    /* check for return code so we can send an alert */\n    if (ret < SSL_OK && ret != SSL_CLOSE_NOTIFY)\n    {\n        if (ret != SSL_ERROR_CONN_LOST)\n        {\n            send_alert(ssl, ret);\n#ifndef CONFIG_SSL_SKELETON_MODE\n            /* something nasty happened, so get rid of this session */\n            kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl);\n#endif\n        }\n    }\n\n    return ret;\n}\n\n/*\n * Write application data to the client\n */\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_write(SSL *ssl, const uint8_t *out_data, int out_len)\n{\n    int n = out_len, nw, i, tot = 0;\n\n    /* maximum size of a TLS packet is around 16kB, so fragment */\n    do \n    {\n        nw = n;\n\n        if (nw > RT_MAX_PLAIN_LENGTH)    /* fragment if necessary */\n            nw = RT_MAX_PLAIN_LENGTH;\n\n        if ((i = send_packet(ssl, PT_APP_PROTOCOL_DATA, \n                                            &out_data[tot], nw)) <= 0)\n        {\n            out_len = i;    /* an error */\n            break;\n        }\n\n        tot += i;\n        n -= i;\n    } while (n > 0);\n\n    return out_len;\n}\n\n/**\n * Add a certificate to the certificate chain.\n */\nint ICACHE_FLASH_ATTR add_cert(SSL_CTX *ssl_ctx, const uint8_t *buf, int len)\n{\n    int ret = SSL_ERROR_NO_CERT_DEFINED, i = 0;\n    SSL_CERT *ssl_cert;\n    X509_CTX *cert = NULL;\n    int offset;\n\n    while (ssl_ctx->certs[i].buf && i < CONFIG_SSL_MAX_CERTS) \n        i++;\n\n    if (i == CONFIG_SSL_MAX_CERTS) /* too many certs */\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"Error: maximum number of certs added (%d) - change of \"\n                \"compile-time configuration required\\n\",\n                CONFIG_SSL_MAX_CERTS);\n#endif\n        goto error;\n    }\n\n    if ((ret = x509_new(buf, &offset, &cert)))\n        goto error;\n\n#if defined (CONFIG_SSL_FULL_MODE)\n    if (ssl_ctx->options & SSL_DISPLAY_CERTS)\n        x509_print(cert, NULL);\n#endif\n\n    ssl_cert = &ssl_ctx->certs[i];\n    ssl_cert->size = len;\n    ssl_cert->buf = (uint8_t *)os_malloc(len);\n    os_memcpy(ssl_cert->buf, buf, len);\n    ssl_ctx->chain_length++;\n    len -= offset;\n    ret = SSL_OK;           /* ok so far */\n\n    /* recurse? */\n    if (len > 0)\n    {\n        ret = add_cert(ssl_ctx, &buf[offset], len);\n    }\n\nerror:\n    x509_free(cert);        /* don't need anymore */\n    return ret;\n}\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n/**\n * Add a certificate authority.\n */\nint ICACHE_FLASH_ATTR add_cert_auth(SSL_CTX *ssl_ctx, const uint8_t *buf, int len)\n{\n    int ret = SSL_OK; /* ignore errors for now */\n    int i = 0;\n    CA_CERT_CTX *ca_cert_ctx;\n\n    if (ssl_ctx->ca_cert_ctx == NULL)\n        ssl_ctx->ca_cert_ctx = (CA_CERT_CTX *)os_zalloc(sizeof(CA_CERT_CTX));\n\n    ca_cert_ctx = ssl_ctx->ca_cert_ctx;\n\n    while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) \n        i++;\n\n    while (len > 0)\n    {\n        int offset;\n        if (i >= CONFIG_X509_MAX_CA_CERTS)\n        {\n#ifdef CONFIG_SSL_FULL_MODE\n            ssl_printf(\"Error: maximum number of CA certs added (%d) - change of \"\n                    \"compile-time configuration required\\n\", \n                    CONFIG_X509_MAX_CA_CERTS);\n#endif\n            break;\n        }\n\n\n        /* ignore the return code */\n        if (x509_new(buf, &offset, &ca_cert_ctx->cert[i]) == X509_OK)\n        {\n#if defined (CONFIG_SSL_FULL_MODE)\n            if (ssl_ctx->options & SSL_DISPLAY_CERTS)\n                x509_print(ca_cert_ctx->cert[i], NULL);\n#endif\n        }\n\n        i++;\n        len -= offset;\n    }\n\n    return ret;\n}\n\n/*\n * Retrieve an X.509 distinguished name component\n */\nEXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_get_cert_dn(const SSL *ssl, int component)\n{\n    if (ssl->x509_ctx == NULL)\n        return NULL;\n\n    switch (component)\n    {\n        case SSL_X509_CERT_COMMON_NAME:\n            return ssl->x509_ctx->cert_dn[X509_COMMON_NAME];\n\n        case SSL_X509_CERT_ORGANIZATION:\n            return ssl->x509_ctx->cert_dn[X509_ORGANIZATION];\n\n        case SSL_X509_CERT_ORGANIZATIONAL_NAME:       \n            return ssl->x509_ctx->cert_dn[X509_ORGANIZATIONAL_UNIT];\n\n        case SSL_X509_CA_CERT_COMMON_NAME:\n            return ssl->x509_ctx->ca_cert_dn[X509_COMMON_NAME];\n\n        case SSL_X509_CA_CERT_ORGANIZATION:\n            return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATION];\n\n        case SSL_X509_CA_CERT_ORGANIZATIONAL_NAME:       \n            return ssl->x509_ctx->ca_cert_dn[X509_ORGANIZATIONAL_UNIT];\n\n        default:\n            return NULL;\n    }\n}\n\n/*\n * Retrieve a \"Subject Alternative Name\" from a v3 certificate\n */\nEXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_get_cert_subject_alt_dnsname(const SSL *ssl,\n        int dnsindex)\n{\n    int i;\n\n    if (ssl->x509_ctx == NULL || ssl->x509_ctx->subject_alt_dnsnames == NULL)\n        return NULL;\n\n    for (i = 0; i < dnsindex; ++i)\n    {\n        if (ssl->x509_ctx->subject_alt_dnsnames[i] == NULL)\n            return NULL;\n    }\n\n    return ssl->x509_ctx->subject_alt_dnsnames[dnsindex];\n}\n\n#endif /* CONFIG_SSL_CERT_VERIFICATION */\n#if 0\n/*\n * Find an ssl object based on the client's file descriptor.\n */\nEXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_find(SSL_CTX *ssl_ctx, int client_fd)\n{\n    SSL *ssl;\n\n    SSL_CTX_LOCK(ssl_ctx->mutex);\n    ssl = ssl_ctx->head;\n\n    /* search through all the ssl entries */\n    while (ssl)\n    {\n        if (ssl->client_fd == client_fd)\n        {\n            SSL_CTX_UNLOCK(ssl_ctx->mutex);\n            return ssl;\n        }\n\n        ssl = ssl->next;\n    }\n\n    SSL_CTX_UNLOCK(ssl_ctx->mutex);\n    return NULL;\n}\n#endif\n/*\n * Force the client to perform its handshake again.\n */\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_renegotiate(SSL *ssl)\n{\n    int ret = SSL_OK;\n\n    disposable_new(ssl);\n#ifdef CONFIG_SSL_ENABLE_CLIENT\n    if (IS_SET_SSL_FLAG(SSL_IS_CLIENT))\n    {\n        ret = do_client_connect(ssl);\n    }\n    else\n#endif\n    {\n        send_packet(ssl, PT_HANDSHAKE_PROTOCOL, \n                g_hello_request, sizeof(g_hello_request));\n        SET_SSL_FLAG(SSL_NEED_RECORD);\n    }\n\n    return ret;\n}\n\n/**\n * @brief Get what we need for key info.\n * @param cipher    [in]    The cipher information we are after\n * @param key_size  [out]   The key size for the cipher\n * @param iv_size   [out]   The iv size for the cipher\n * @return  The amount of key information we need.\n */\nstatic const cipher_info_t *ICACHE_FLASH_ATTR get_cipher_info(uint8_t cipher)\n{\n    int i;\n\n    for (i = 0; i < NUM_PROTOCOLS; i++)\n    {\n        if (cipher_info[i].cipher == cipher)\n        {\n            return &cipher_info[i];\n        }\n    }\n\n    return NULL;  /* error */\n}\n\n#if 0\n/*\n * Get a new ssl context for a new connection.\n */\nSSL *ICACHE_FLASH_ATTR ssl_new(SSL_CTX *ssl_ctx, int client_fd)\n{\n    SSL *ssl = (SSL *)os_zalloc(sizeof(SSL));\n    ssl->ssl_ctx = ssl_ctx;\n    ssl->need_bytes = SSL_RECORD_SIZE;      /* need a record */\n    ssl->client_fd = client_fd;\n    ssl->flag = SSL_NEED_RECORD;\n    ssl->bm_data = ssl->bm_all_data+BM_RECORD_OFFSET; /* space at the start */\n    ssl->hs_status = SSL_NOT_OK;            /* not connected */\n#ifdef CONFIG_ENABLE_VERIFICATION\n    ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx;\n#endif\n    disposable_new(ssl);\n\n    /* a bit hacky but saves a few bytes of memory */\n    ssl->flag |= ssl_ctx->options;\n    SSL_CTX_LOCK(ssl_ctx->mutex);\n\n    if (ssl_ctx->head == NULL)\n    {\n        ssl_ctx->head = ssl;\n        ssl_ctx->tail = ssl;\n    }\n    else\n    {\n        ssl->prev = ssl_ctx->tail;\n        ssl_ctx->tail->next = ssl;\n        ssl_ctx->tail = ssl;\n    }\n\n    SSL_CTX_UNLOCK(ssl_ctx->mutex);\n    return ssl;\n}\n#endif\n\n/*\n * Get a new ssl context for a new connection.(raw api)add by ives 12.12.2013\n */\nSSL *ICACHE_FLASH_ATTR ssl_new_context(SSL_CTX *ssl_ctx, struct tcp_pcb *SslClient_pcb)\n{\n\tSSL *ssl = (SSL *)os_zalloc(sizeof(SSL));\n    ssl->ssl_ctx = ssl_ctx;\n    ssl->need_bytes = SSL_RECORD_SIZE;      /* need a record */\n    //ssl->client_fd = client_fd;annotation by ives 12.12.2013\n    ssl->SslClient_pcb = SslClient_pcb;\n\tssl->ssl_pbuf = NULL;\n    ssl->flag = SSL_NEED_RECORD;\n    ssl->bm_data = ssl->bm_all_data + BM_RECORD_OFFSET; /* space at the start */\n    ssl->hs_status = SSL_NOT_OK;            /* not connected */\n#ifdef CONFIG_ENABLE_VERIFICATION\n    ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx;\n#endif\n    disposable_new(ssl);\n    /* a bit hacky but saves a few bytes of memory */\n    ssl->flag |= ssl_ctx->options;\n    SSL_CTX_LOCK(ssl_ctx->mutex);\n    if (ssl_ctx->head == NULL) {\n        ssl_ctx->head = ssl;\n        ssl_ctx->tail = ssl;\n    } else {\n        ssl->prev = ssl_ctx->tail;\n        ssl_ctx->tail->next = ssl;\n        ssl_ctx->tail = ssl;\n    }\n    SSL_CTX_UNLOCK(ssl_ctx->mutex);\n    return ssl;\n}\n/*\n * Add a private key to a context.\n */\nint ICACHE_FLASH_ATTR add_private_key(SSL_CTX *ssl_ctx, SSLObjLoader *ssl_obj)\n{\n    int ret = SSL_OK;\n\n    /* get the private key details */\n    if (asn1_get_private_key(ssl_obj->buf, ssl_obj->len, &ssl_ctx->rsa_ctx))\n    {\n        ret = SSL_ERROR_INVALID_KEY;\n        goto error;\n    }\n\nerror:\n    return ret;\n}\n\n/** \n * Increment the read sequence number (as a 64 bit endian indepenent #)\n */     \nstatic void ICACHE_FLASH_ATTR increment_read_sequence(SSL *ssl)\n{\n    int i;\n\n    for (i = 7; i >= 0; i--) \n    {       \n        if (++ssl->read_sequence[i])\n            break;\n    }\n}\n            \n/**\n * Increment the read sequence number (as a 64 bit endian indepenent #)\n */      \nstatic void ICACHE_FLASH_ATTR increment_write_sequence(SSL *ssl)\n{        \n    int i;                  \n         \n    for (i = 7; i >= 0; i--)\n    {                       \n        if (++ssl->write_sequence[i])\n            break;\n    }                       \n}\n\n/**\n * Work out the HMAC digest in a packet.\n */\nstatic void ICACHE_FLASH_ATTR add_hmac_digest(SSL *ssl, int mode, uint8_t *hmac_header,\n        const uint8_t *buf, int buf_len, uint8_t *hmac_buf)\n{\n    int hmac_len = buf_len + 8 + SSL_RECORD_SIZE;\n    uint8_t *t_buf = (uint8_t *)os_malloc(hmac_len+10);\n\n    os_memcpy(t_buf, (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE) ? \n                    ssl->write_sequence : ssl->read_sequence, 8);\n    os_memcpy(&t_buf[8], hmac_header, SSL_RECORD_SIZE);\n    os_memcpy(&t_buf[8+SSL_RECORD_SIZE], buf, buf_len);\n\n    ssl->cipher_info->hmac(t_buf, hmac_len, \n            (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ) ? \n                ssl->server_mac : ssl->client_mac, \n            ssl->cipher_info->digest_size, hmac_buf);\n\n    /* add by wujg */\n    os_free(t_buf);\n    \n#if 0\n    print_blob(\"record\", hmac_header, SSL_RECORD_SIZE);\n    print_blob(\"buf\", buf, buf_len);\n    if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_WRITE)\n    {\n        print_blob(\"write seq\", ssl->write_sequence, 8);\n    }\n    else\n    {\n        print_blob(\"read seq\", ssl->read_sequence, 8);\n    }\n\n    if (mode == SSL_SERVER_WRITE || mode == SSL_CLIENT_READ)\n    {\n        print_blob(\"server mac\", \n                ssl->server_mac, ssl->cipher_info->digest_size);\n    }\n    else\n    {\n        print_blob(\"client mac\", \n                ssl->client_mac, ssl->cipher_info->digest_size);\n    }\n    print_blob(\"hmac\", hmac_buf, SHA1_SIZE);\n#endif\n}\n\n/**\n * Verify that the digest of a packet is correct.\n */\nstatic int ICACHE_FLASH_ATTR verify_digest(SSL *ssl, int mode, const uint8_t *buf, int read_len)\n{   \n    uint8_t hmac_buf[SHA1_SIZE];\n    int hmac_offset;\n   \n    if (ssl->cipher_info->padding_size)\n    {\n        int last_blk_size = buf[read_len-1], i;\n        hmac_offset = read_len-last_blk_size-ssl->cipher_info->digest_size-1;\n\n        /* guard against a timing attack - make sure we do the digest */\n        if (hmac_offset < 0)\n        {\n            hmac_offset = 0;\n        }\n        else\n        {\n            /* already looked at last byte */\n            for (i = 1; i < last_blk_size; i++)\n            {\n                if (buf[read_len-i] != last_blk_size)\n                {\n                    hmac_offset = 0;\n                    break;\n                }\n            }\n        }\n    }\n    else /* stream cipher */\n    {\n        hmac_offset = read_len - ssl->cipher_info->digest_size;\n\n        if (hmac_offset < 0)\n        {\n            hmac_offset = 0;\n        }\n    }\n\n    /* sanity check the offset */\n    ssl->hmac_header[3] = hmac_offset >> 8;      /* insert size */\n    ssl->hmac_header[4] = hmac_offset & 0xff;\n    add_hmac_digest(ssl, mode, ssl->hmac_header, buf, hmac_offset, hmac_buf);\n\n    if (memcmp(hmac_buf, &buf[hmac_offset], ssl->cipher_info->digest_size))\n    {\n        return SSL_ERROR_INVALID_HMAC;\n    }\n\n    return hmac_offset;\n}\n\n/**\n * Add a packet to the end of our sent and received packets, so that we may use\n * it to calculate the hash at the end.\n */\nvoid ICACHE_FLASH_ATTR add_packet(SSL *ssl, const uint8_t *pkt, int len)\n{\n    MD5_Update(&ssl->dc->md5_ctx, pkt, len);\n    SHA1_Update(&ssl->dc->sha1_ctx, pkt, len);\n}\n\n/**\n * Work out the MD5 PRF.\n */\nstatic void ICACHE_FLASH_ATTR p_hash_md5(const uint8_t *sec, int sec_len, \n        uint8_t *seed, int seed_len, uint8_t *out, int olen)\n{\n    uint8_t a1[128];\n\n    /* A(1) */\n    ssl_hmac_md5(seed, seed_len, sec, sec_len, a1);\n    os_memcpy(&a1[MD5_SIZE], seed, seed_len);\n    ssl_hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out);\n\n    while (olen > MD5_SIZE)\n    {\n        uint8_t a2[MD5_SIZE];\n        out += MD5_SIZE;\n        olen -= MD5_SIZE;\n\n        /* A(N) */\n        ssl_hmac_md5(a1, MD5_SIZE, sec, sec_len, a2);\n        os_memcpy(a1, a2, MD5_SIZE);\n\n        /* work out the actual hash */\n        ssl_hmac_md5(a1, MD5_SIZE+seed_len, sec, sec_len, out);\n    }\n}\n\n/**\n * Work out the SHA1 PRF.\n */\nstatic void ICACHE_FLASH_ATTR p_hash_sha1(const uint8_t *sec, int sec_len, \n        uint8_t *seed, int seed_len, uint8_t *out, int olen)\n{\n    uint8_t a1[128];\n\n    /* A(1) */\n    ssl_hmac_sha1(seed, seed_len, sec, sec_len, a1);\n    os_memcpy(&a1[SHA1_SIZE], seed, seed_len);\n    ssl_hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out);\n\n    while (olen > SHA1_SIZE)\n    {\n        uint8_t a2[SHA1_SIZE];\n        out += SHA1_SIZE;\n        olen -= SHA1_SIZE;\n\n        /* A(N) */\n        ssl_hmac_sha1(a1, SHA1_SIZE, sec, sec_len, a2);\n        os_memcpy(a1, a2, SHA1_SIZE);\n\n        /* work out the actual hash */\n        ssl_hmac_sha1(a1, SHA1_SIZE+seed_len, sec, sec_len, out);\n    }\n}\n\n/**\n * Work out the PRF.\n */\nstatic void ICACHE_FLASH_ATTR prf(const uint8_t *sec, int sec_len, uint8_t *seed, int seed_len,\n        uint8_t *out, int olen)\n{\n    int len, i;\n    const uint8_t *S1, *S2;\n    uint8_t xbuf[256]; /* needs to be > the amount of key data */\n    uint8_t ybuf[256]; /* needs to be > the amount of key data */\n\n    len = sec_len/2;\n    S1 = sec;\n    S2 = &sec[len];\n    len += (sec_len & 1); /* add for odd, make longer */\n\n    p_hash_md5(S1, len, seed, seed_len, xbuf, olen);\n    p_hash_sha1(S2, len, seed, seed_len, ybuf, olen);\n\n    for (i = 0; i < olen; i++)\n        out[i] = xbuf[i] ^ ybuf[i];\n}\n\n/**\n * Generate a master secret based on the client/server random data and the\n * premaster secret.\n */\nvoid ICACHE_FLASH_ATTR generate_master_secret(SSL *ssl, const uint8_t *premaster_secret)\n{\n    uint8_t buf[128];   /* needs to be > 13+32+32 in size */\n    os_strcpy((char *)buf, \"master secret\");\n    os_memcpy(&buf[13], ssl->dc->client_random, SSL_RANDOM_SIZE);\n    os_memcpy(&buf[45], ssl->dc->server_random, SSL_RANDOM_SIZE);\n    prf(premaster_secret, SSL_SECRET_SIZE, buf, 77, ssl->dc->master_secret,\n            SSL_SECRET_SIZE);\n}\n\n/**\n * Generate a 'random' blob of data used for the generation of keys.\n */\nstatic void ICACHE_FLASH_ATTR generate_key_block(uint8_t *client_random, uint8_t *server_random,\n        uint8_t *master_secret, uint8_t *key_block, int key_block_size)\n{\n    uint8_t buf[128];\n    os_strcpy((char *)buf, \"key expansion\");\n    os_memcpy(&buf[13], server_random, SSL_RANDOM_SIZE);\n    os_memcpy(&buf[45], client_random, SSL_RANDOM_SIZE);\n    prf(master_secret, SSL_SECRET_SIZE, buf, 77, key_block, key_block_size);\n}\n\n/** \n * Calculate the digest used in the finished message. This function also\n * doubles up as a certificate verify function.\n */\nvoid ICACHE_FLASH_ATTR finished_digest(SSL *ssl, const char *label, uint8_t *digest)\n{\n    uint8_t mac_buf[128]; \n    uint8_t *q = mac_buf;\n    MD5_CTX md5_ctx = ssl->dc->md5_ctx;\n    SHA1_CTX sha1_ctx = ssl->dc->sha1_ctx;\n\n    if (label)\n    {\n        os_strcpy((char *)q, label);\n        q += os_strlen(label);\n    }\n\n    MD5_Final(q, &md5_ctx);\n    q += MD5_SIZE;\n    \n    SHA1_Final(q, &sha1_ctx);\n    q += SHA1_SIZE;\n\n    if (label)\n    {\n        prf(ssl->dc->master_secret, SSL_SECRET_SIZE, mac_buf, (int)(q-mac_buf),\n            digest, SSL_FINISHED_HASH_SIZE);\n    }\n    else    /* for use in a certificate verify */\n    {\n        os_memcpy(digest, mac_buf, MD5_SIZE + SHA1_SIZE);\n    }\n\n#if 0\n    printf(\"label: %s\\n\", label);\n    print_blob(\"master secret\", ssl->dc->master_secret, 48);\n    print_blob(\"mac_buf\", mac_buf, q-mac_buf);\n    print_blob(\"finished digest\", digest, SSL_FINISHED_HASH_SIZE);\n#endif\n}   \n    \n/**\n * Retrieve (and initialise) the context of a cipher.\n */\nstatic void *ICACHE_FLASH_ATTR crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt)\n{\n    switch (ssl->cipher)\n    {\n#ifndef CONFIG_SSL_SKELETON_MODE\n        case SSL_AES128_SHA:\n            {\n                AES_CTX *aes_ctx = (AES_CTX *)os_malloc(sizeof(AES_CTX));\n                AES_set_key(aes_ctx, key, iv, AES_MODE_128);\n\n                if (is_decrypt)\n                {\n                    AES_convert_key(aes_ctx);\n                }\n\n                return (void *)aes_ctx;\n            }\n\n        case SSL_AES256_SHA:\n            {\n                AES_CTX *aes_ctx = (AES_CTX *)os_malloc(sizeof(AES_CTX));\n                AES_set_key(aes_ctx, key, iv, AES_MODE_256);\n\n                if (is_decrypt)\n                {\n                    AES_convert_key(aes_ctx);\n                }\n\n                return (void *)aes_ctx;\n            }\n\n        case SSL_RC4_128_MD5:\n#endif\n        case SSL_RC4_128_SHA:\n            {\n                RC4_CTX *rc4_ctx = (RC4_CTX *)os_malloc(sizeof(RC4_CTX));\n                RC4_setup(rc4_ctx, key, 16);\n                return (void *)rc4_ctx;\n            }\n    }\n\n    return NULL;    /* its all gone wrong */\n}\n\n/**\n * Send a packet over the socket.\n */\nstatic err_t ICACHE_FLASH_ATTR send_raw_packet(SSL *ssl, uint8_t protocol)\n{\n    uint8_t *rec_buf = ssl->bm_all_data;\n    int pkt_size = SSL_RECORD_SIZE + ssl->bm_index;\n    int Length = 0;\n    //int ret = SSL_OK;\n    err_t Err = ERR_OK;\n    rec_buf[0] = protocol;\n    rec_buf[1] = 0x03;      /* version = 3.1 or higher */\n    rec_buf[2] = ssl->version & 0x0f;\n    rec_buf[3] = ssl->bm_index >> 8;\n    rec_buf[4] = ssl->bm_index & 0xff;\n    //DISPLAY_BYTES(ssl, \"sending %d bytes\", ssl->bm_all_data,\n    //              pkt_size, pkt_size);\n\n\tssl_printf(\"send_raw_packet pkt_size %d\\n\", pkt_size);\n    if(tcp_sndbuf(ssl->SslClient_pcb) < pkt_size) {\n        Length = tcp_sndbuf(ssl->SslClient_pcb);\n    } else {\n        Length = pkt_size;\n    }\n    if(Length > 2 * ssl->SslClient_pcb->mss) {\n        Length = 2 * ssl->SslClient_pcb->mss;\n    }\n    do {\n        Err = tcp_write(ssl->SslClient_pcb, &ssl->bm_all_data[0], Length, 0);\n        if (Err == ERR_MEM) {\n            Length /= 2;\n        }\n    } while(Err == ERR_MEM && Length > 1);\n    ssl_printf(\"send_raw_packet Length %d\\n\", Length);\n    if (Err == ERR_OK) {\n        Err = tcp_output(ssl->SslClient_pcb);\n    }\n    SET_SSL_FLAG(SSL_NEED_RECORD);  /* reset for next time */\n    //ssl->bm_index = 0;\n    if (protocol != PT_APP_PROTOCOL_DATA) {\n        /* always return SSL_OK during handshake */\n    \tssl->bm_index = 0;\n        Err = SSL_OK;\n    }\n    return Err;\n}\n\n/**\n * Send an encrypted packet with padding bytes if necessary.\n */\nint ICACHE_FLASH_ATTR send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length)\n{\n    int ret, msg_length = 0;\n\n    /* if our state is bad, don't bother */\n    if (ssl->hs_status == SSL_ERROR_DEAD)\n        return SSL_ERROR_CONN_LOST;\n\n    if (in) /* has the buffer already been initialised? */\n    {\n        os_memcpy(ssl->bm_data, in, length);\n    }\n\n    msg_length += length;\n\n    if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED))\n    {\n        int mode = IS_SET_SSL_FLAG(SSL_IS_CLIENT) ? \n                            SSL_CLIENT_WRITE : SSL_SERVER_WRITE;\n        uint8_t hmac_header[SSL_RECORD_SIZE] = \n        {\n            protocol, \n            0x03, /* version = 3.1 or higher */\n            ssl->version & 0x0f,\n            msg_length >> 8,\n            msg_length & 0xff \n        };\n\n        if (protocol == PT_HANDSHAKE_PROTOCOL)\n        {\n            //DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);\n\n            if (ssl->bm_data[0] != HS_HELLO_REQUEST)\n            {\n                add_packet(ssl, ssl->bm_data, msg_length);\n            }\n        }\n\n        /* add the packet digest */\n        add_hmac_digest(ssl, mode, hmac_header, ssl->bm_data, msg_length, \n                                                &ssl->bm_data[msg_length]);\n        msg_length += ssl->cipher_info->digest_size;\n\n        /* add padding? */\n        if (ssl->cipher_info->padding_size)\n        {\n            int last_blk_size = msg_length%ssl->cipher_info->padding_size;\n            int pad_bytes = ssl->cipher_info->padding_size - last_blk_size;\n\n            /* ensure we always have at least 1 padding byte */\n            if (pad_bytes == 0)\n                pad_bytes += ssl->cipher_info->padding_size;\n\n            os_memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes);\n            msg_length += pad_bytes;\n        }\n\n        //DISPLAY_BYTES(ssl, \"unencrypted write\", ssl->bm_data, msg_length);\n        increment_write_sequence(ssl);\n\n        /* add the explicit IV for TLS1.1 */\n        if (ssl->version >= SSL_PROTOCOL_VERSION1_1 &&\n                        ssl->cipher_info->iv_size)\n        {\n            uint8_t iv_size = ssl->cipher_info->iv_size;\n            uint8_t *t_buf = (uint8_t *)os_malloc(msg_length + iv_size);\n            os_memcpy(t_buf + iv_size, ssl->bm_data, msg_length);\n            get_random(iv_size, t_buf);\n            msg_length += iv_size;\n            os_memcpy(ssl->bm_data, t_buf, msg_length);\n            os_free(t_buf); /* add by wujg */\n        }\n\n        /* now encrypt the packet */\n        ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data, \n                                            ssl->bm_data, msg_length);\n    }\n    else if (protocol == PT_HANDSHAKE_PROTOCOL)\n    {\n        //DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0);\n\n        if (ssl->bm_data[0] != HS_HELLO_REQUEST)\n        {\n            add_packet(ssl, ssl->bm_data, length);\n        }\n    }\n\n    ssl->bm_index = msg_length;\n    if ((ret = send_raw_packet(ssl, protocol)) <= 0)\n        return ret;\n\n    return length;  /* just return what we wanted to send */\n}\n\n/**\n * Work out the cipher keys we are going to use for this session based on the\n * master secret.\n */\nstatic int ICACHE_FLASH_ATTR set_key_block(SSL *ssl, int is_write)\n{\n    const cipher_info_t *ciph_info = get_cipher_info(ssl->cipher);\n    uint8_t *q;\n    uint8_t client_key[32], server_key[32]; /* big enough for AES256 */\n    uint8_t client_iv[16], server_iv[16];   /* big enough for AES128/256 */\n    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);\n\n    if (ciph_info == NULL)\n        return -1;\n\n    /* only do once in a handshake */\n    if (ssl->dc->key_block == NULL)\n    {\n        ssl->dc->key_block = (uint8_t *)os_malloc(ciph_info->key_block_size);\n\n#if 0\n        print_blob(\"client\", ssl->dc->client_random, 32);\n        print_blob(\"server\", ssl->dc->server_random, 32);\n        print_blob(\"master\", ssl->dc->master_secret, SSL_SECRET_SIZE);\n#endif\n        generate_key_block(ssl->dc->client_random, ssl->dc->server_random,\n            ssl->dc->master_secret, ssl->dc->key_block, \n            ciph_info->key_block_size);\n#if 0\n        print_blob(\"keyblock\", ssl->dc->key_block, ciph_info->key_block_size);\n#endif\n    }\n\n    q = ssl->dc->key_block;\n\n    if ((is_client && is_write) || (!is_client && !is_write))\n    {\n        os_memcpy(ssl->client_mac, q, ciph_info->digest_size);\n    }\n\n    q += ciph_info->digest_size;\n\n    if ((!is_client && is_write) || (is_client && !is_write))\n    {\n        os_memcpy(ssl->server_mac, q, ciph_info->digest_size);\n    }\n\n    q += ciph_info->digest_size;\n    os_memcpy(client_key, q, ciph_info->key_size);\n    q += ciph_info->key_size;\n    os_memcpy(server_key, q, ciph_info->key_size);\n    q += ciph_info->key_size;\n\n#ifndef CONFIG_SSL_SKELETON_MODE \n    if (ciph_info->iv_size)    /* RC4 has no IV, AES does */\n    {\n        os_memcpy(client_iv, q, ciph_info->iv_size);\n        q += ciph_info->iv_size;\n        os_memcpy(server_iv, q, ciph_info->iv_size);\n        q += ciph_info->iv_size;\n    }\n#endif\n\n    os_free(is_write ? ssl->encrypt_ctx : ssl->decrypt_ctx);\n\n    /* now initialise the ciphers */\n    if (is_client)\n    {\n        finished_digest(ssl, server_finished, ssl->dc->final_finish_mac);\n\n        if (is_write)\n            ssl->encrypt_ctx = crypt_new(ssl, client_key, client_iv, 0);\n        else\n            ssl->decrypt_ctx = crypt_new(ssl, server_key, server_iv, 1);\n    }\n    else\n    {\n        finished_digest(ssl, client_finished, ssl->dc->final_finish_mac);\n\n        if (is_write)\n            ssl->encrypt_ctx = crypt_new(ssl, server_key, server_iv, 0);\n        else\n            ssl->decrypt_ctx = crypt_new(ssl, client_key, client_iv, 1);\n    }\n\n    ssl->cipher_info = ciph_info;\n    return 0;\n}\n\n/**\n * Read the SSL connection.\n */\nint ICACHE_FLASH_ATTR basic_read(SSL *ssl, uint8_t **in_data)\n{\nint ret = SSL_OK;\n\tint j,i = 0;\n    int read_len, is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);\n    uint8_t *buf = ssl->bm_data;\n\tuint8_t *read_buf = NULL;\n\tuint8_t *pread_buf = NULL;\n\tu16_t recvlength = 0;\n\tread_buf =(uint8_t*)os_zalloc(ssl->ssl_pbuf->len + 1);\n\tpread_buf = read_buf;\n\tif (pread_buf != NULL){\n\t\trecvlength = pbuf_copy_partial(ssl->ssl_pbuf, read_buf,ssl->ssl_pbuf->len,0);\n\t}\n\tif (recvlength != 0){\n\t\tdo{\t\n//\t\t\tssl_printf(\"basic_read ssl->bm_read_index %d\\n\", ssl->bm_read_index);\n//\t\t\tssl_printf(\"basic_read ssl->need_bytes %d\\n\", ssl->need_bytes);\n//\t\t\tssl_printf(\"basic_read ssl->got_bytes %d\\n\", ssl->got_bytes);\n\t\t\tread_len = ssl->need_bytes - ssl->got_bytes;\t\t\t\t\t\t\n\t\t\tif (read_len >= recvlength){\n\t\t\t\tread_len = recvlength;\n\t\t\t}\t\t\t\n\t\t\tos_memcpy(&buf[ssl->bm_read_index],read_buf, read_len);\n//\t\t\tssl_printf(\"basic_read read_len %d\\n\", read_len);\n//\t\t\tfor (i = ssl->bm_read_index; i < (ssl->bm_read_index + read_len); i ++){\n//\t\t\t\tssl_printf(\"%2x \",buf[i]);\n//\t\t\t\tif ((i + 1) % 16 == 0)\n//\t\t\t\t\tssl_printf(\"\\n\");\n//\t\t\t}\n//\t\t\tssl_printf(\"\\n\");\n\t\t\t\n\t\t\tread_buf += read_len;\n\t\t\trecvlength -= read_len;\n//\t\t\tssl_printf(\"basic_read %d %d\\n\", __LINE__, recvlength);\n    /* connection has gone, so die */\n    if (read_len <= 0)\n    {\n        ret = SSL_ERROR_CONN_LOST;\n        ssl->hs_status = SSL_ERROR_DEAD;  /* make sure it stays dead */\n        goto error;\n    }\n\n    //DISPLAY_BYTES(ssl, \"received %d bytes\", \n    //        &ssl->bm_data[ssl->bm_read_index], read_len, read_len);\n\n    ssl->got_bytes += read_len;\n    ssl->bm_read_index += read_len;\n\n    /* haven't quite got what we want, so try again later */\n    if (ssl->got_bytes < ssl->need_bytes){\n//\t\tssl_printf(\"basic_read %d %p\\n\", __LINE__, pread_buf);\n\t\tos_free(pread_buf);\n\t\tpread_buf = NULL;\n        return SSL_OK;\n    }\n    read_len = ssl->got_bytes;\n    ssl->got_bytes = 0;\n\n    if (IS_SET_SSL_FLAG(SSL_NEED_RECORD))\n    {\n        /* check for sslv2 \"client hello\" */\n        if (buf[0] & 0x80 && buf[2] == 1)\n        {\n#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE\n            uint8_t version = (buf[3] << 4) + buf[4];\n            DISPLAY_BYTES(ssl, \"ssl2 record\", buf, 5);\n\n            /* should be v3.1 (TLSv1) or better  */\n            ssl->version = ssl->client_version = version;\n\n            if (version > SSL_PROTOCOL_VERSION_MAX)\n            {\n                /* use client's version */\n                ssl->version = SSL_PROTOCOL_VERSION_MAX;\n            }\n            else if (version < SSL_PROTOCOL_MIN_VERSION)  \n            {\n                ret = SSL_ERROR_INVALID_VERSION;\n                ssl_display_error(ret);\n                return ret;\n            }\n\n            add_packet(ssl, &buf[2], 3);\n            ret = process_sslv23_client_hello(ssl); \n#else\n            ssl_printf(\"Error: no SSLv23 handshaking allowed\\n\"); //TTY_FLUSH();\n            ret = SSL_ERROR_NOT_SUPPORTED;\n#endif\n            goto error; /* not an error - just get out of here */\n        }\n\n        ssl->need_bytes = (buf[3] << 8) + buf[4];\n\n        /* do we violate the spec with the message size?  */\n        if (ssl->need_bytes > RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET)\n        {\n            ret = SSL_ERROR_INVALID_PROT_MSG;\n            recvlength = 0;\n            os_printf(\"we violate the spec with the message size\\n\");\n            goto error;\n        }\n\n        CLR_SSL_FLAG(SSL_NEED_RECORD);\n        os_memcpy(ssl->hmac_header, buf, 3);       /* store for hmac */\n        ssl->record_type = buf[0];\n        goto error;                         /* no error, we're done */\n    }\n\n    /* for next time - just do it now in case of an error */\n    SET_SSL_FLAG(SSL_NEED_RECORD);\n    ssl->need_bytes = SSL_RECORD_SIZE;\n\n    /* decrypt if we need to */\n    if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED))\n    {\n        ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, read_len);\n\n        if (ssl->version >= SSL_PROTOCOL_VERSION1_1 &&\n                        ssl->cipher_info->iv_size)\n        {\n            buf += ssl->cipher_info->iv_size;\n            read_len -= ssl->cipher_info->iv_size;\n        }\n\n        read_len = verify_digest(ssl, \n                is_client ? SSL_CLIENT_READ : SSL_SERVER_READ, buf, read_len);\n\n        /* does the hmac work? */\n        if (read_len < 0)\n        {\n            ret = read_len;\n            goto error;\n        }\n\n        //DISPLAY_BYTES(ssl, \"decrypted\", buf, read_len);\n        increment_read_sequence(ssl);\n    }\n\n    /* The main part of the SSL packet */\n\t//ssl_printf(\"basic_read %d %x %p\\n\", __LINE__, ssl->record_type, in_data);\n    switch (ssl->record_type)\n    {\n        case PT_HANDSHAKE_PROTOCOL:\n            if (ssl->dc != NULL)\n            {\n                ssl->dc->bm_proc_index = 0;\n                ret = do_handshake(ssl, buf, read_len);\n            }\n            else /* no client renegotiation allowed */\n            {\n                ret = SSL_ERROR_NO_CLIENT_RENOG;\n                goto error;\n            }\n            break;\n\n        case PT_CHANGE_CIPHER_SPEC:\n            if (ssl->next_state != HS_FINISHED)\n            {\n                ret = SSL_ERROR_INVALID_HANDSHAKE;\n                goto error;\n            }\n\n            /* all encrypted from now on */\n            SET_SSL_FLAG(SSL_RX_ENCRYPTED);\n            if (set_key_block(ssl, 0) < 0)\n            {\n                ret = SSL_ERROR_INVALID_HANDSHAKE;\n                goto error;\n            }\n            \n            os_memset(ssl->read_sequence, 0, 8);\n            break;\n\n        case PT_APP_PROTOCOL_DATA:\n            if (in_data)\n            {\n                *in_data = buf;   /* point to the work buffer */\n                (*in_data)[read_len] = 0;  /* null terminate just in case */\n            }\n\n            ret = read_len;\n\t\t\trecvlength = 0;\n            break;\n\n        case PT_ALERT_PROTOCOL:\n            /* return the alert # with alert bit set */\n            if(buf[0] == SSL_ALERT_TYPE_WARNING &&\n               buf[1] == SSL_ALERT_CLOSE_NOTIFY)\n            {\n              ret = SSL_CLOSE_NOTIFY;\n              //send_alert(ssl, SSL_ALERT_CLOSE_NOTIFY);\n              SET_SSL_FLAG(SSL_SENT_CLOSE_NOTIFY);\n            }\n            else \n            {\n                ret = -buf[1]; \n                //DISPLAY_ALERT(ssl, buf[1]);\n            }\n\n            break;\n\n        default:\n            ret = SSL_ERROR_INVALID_PROT_MSG;\n            break;\n    }\n\nerror:\n    ssl->bm_read_index = 0;          /* reset to go again */\n\n    if (ret < SSL_OK && in_data)/* if all wrong, then clear this buffer ptr */\n        *in_data = NULL;\n\t\t}while(recvlength != 0);\n\t}else{\n\t\tssl_printf(\"%s %d %d\\n\", __func__, __LINE__,recvlength);\n\t}\n\tos_free(pread_buf);\n\tpread_buf = NULL;\n\treturn ret;\n}\n\n/**\n * Do some basic checking of data and then perform the appropriate handshaking.\n */\nstatic int ICACHE_FLASH_ATTR do_handshake(SSL *ssl, uint8_t *buf, int read_len)\n{\n    int hs_len = (buf[2]<<8) + buf[3];\n    uint8_t handshake_type = buf[0];\n    int ret = SSL_OK;\n    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);\n\n    /* some integrity checking on the handshake */\n    PARANOIA_CHECK(read_len-SSL_HS_HDR_SIZE, hs_len);\n\n    if (handshake_type != ssl->next_state)\n    {\n        /* handle a special case on the client */\n        if (!is_client || handshake_type != HS_CERT_REQ ||\n                        ssl->next_state != HS_SERVER_HELLO_DONE)\n        {\n            ret = SSL_ERROR_INVALID_HANDSHAKE;\n            goto error;\n        }\n    }\n\n    hs_len += SSL_HS_HDR_SIZE;  /* adjust for when adding packets */\n    ssl->bm_index = hs_len;     /* store the size and check later */\n    //DISPLAY_STATE(ssl, 0, handshake_type, 0);\n\n    if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST)\n        add_packet(ssl, buf, hs_len); \n\n#if defined(CONFIG_SSL_ENABLE_CLIENT)\n    ret = is_client ? \n        do_clnt_handshake(ssl, handshake_type, buf, hs_len) :\n        do_svr_handshake(ssl, handshake_type, buf, hs_len);\n#else\n    ret = do_svr_handshake(ssl, handshake_type, buf, hs_len);\n#endif\n\n    /* just use recursion to get the rest */\n    if (hs_len < read_len && ret == SSL_OK)\n        ret = do_handshake(ssl, &buf[hs_len], read_len-hs_len);\n\nerror:\n    return ret;\n}\n\n/**\n * Sends the change cipher spec message. We have just read a finished message\n * from the client.\n */\nint ICACHE_FLASH_ATTR send_change_cipher_spec(SSL *ssl)\n{\n    int ret = send_packet(ssl, PT_CHANGE_CIPHER_SPEC, \n            g_chg_cipher_spec_pkt, sizeof(g_chg_cipher_spec_pkt));\n    SET_SSL_FLAG(SSL_TX_ENCRYPTED);\n\n    if (ret >= 0 && set_key_block(ssl, 1) < 0)\n        ret = SSL_ERROR_INVALID_HANDSHAKE;\n\n    os_memset(ssl->write_sequence, 0, 8);\n    return ret;\n}\n\n/**\n * Send a \"finished\" message\n */\nint ICACHE_FLASH_ATTR send_finished(SSL *ssl)\n{\n    uint8_t buf[SSL_FINISHED_HASH_SIZE+4] = {\n        HS_FINISHED, 0, 0, SSL_FINISHED_HASH_SIZE };\n\n    /* now add the finished digest mac (12 bytes) */\n    finished_digest(ssl, \n        IS_SET_SSL_FLAG(SSL_IS_CLIENT) ?\n                    client_finished : server_finished, &buf[4]);\n\n#ifndef CONFIG_SSL_SKELETON_MODE\n    /* store in the session cache */\n    if (!IS_SET_SSL_FLAG(SSL_SESSION_RESUME) && ssl->ssl_ctx->num_sessions)\n    {\n        os_memcpy(ssl->session->master_secret,\n                ssl->dc->master_secret, SSL_SECRET_SIZE);\n    }\n#endif\n\n    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL,\n                                buf, SSL_FINISHED_HASH_SIZE+4);\n}\n\n/**\n * Send an alert message.\n * Return 1 if the alert was an \"error\".\n */\nint ICACHE_FLASH_ATTR send_alert(SSL *ssl, int error_code)\n{\n    int alert_num = 0;\n    int is_warning = 0;\n    uint8_t buf[2];\n\t\n    /* Don't bother we're already dead */\n    if (ssl->hs_status == SSL_ERROR_DEAD)\n    {\n        return SSL_ERROR_CONN_LOST;\n    }\n\n#ifdef CONFIG_SSL_FULL_MODE\n    //if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))\n        //ssl_display_error(error_code);\n#endif\n\n    switch (error_code)\n    {\n        case SSL_ALERT_CLOSE_NOTIFY:\n            is_warning = 1;\n            alert_num = SSL_ALERT_CLOSE_NOTIFY;\n            break;\n\n        case SSL_ERROR_CONN_LOST:       /* don't send alert just yet */\n            is_warning = 1;\n            break;\n\n        case SSL_ERROR_INVALID_HANDSHAKE:\n        case SSL_ERROR_INVALID_PROT_MSG:\n            alert_num = SSL_ALERT_HANDSHAKE_FAILURE;\n            break;\n\n        case SSL_ERROR_INVALID_HMAC:\n        case SSL_ERROR_FINISHED_INVALID:\n            alert_num = SSL_ALERT_BAD_RECORD_MAC;\n            break;\n\n        case SSL_ERROR_INVALID_VERSION:\n            alert_num = SSL_ALERT_INVALID_VERSION;\n            break;\n\n        case SSL_ERROR_INVALID_SESSION:\n        case SSL_ERROR_NO_CIPHER:\n        case SSL_ERROR_INVALID_KEY:\n            alert_num = SSL_ALERT_ILLEGAL_PARAMETER;\n            break;\n\n        case SSL_ERROR_BAD_CERTIFICATE:\n            alert_num = SSL_ALERT_BAD_CERTIFICATE;\n            break;\n\n        case SSL_ERROR_NO_CLIENT_RENOG:\n            alert_num = SSL_ALERT_NO_RENEGOTIATION;\n            break;\n\n        default:\n            /* a catch-all for any badly verified certificates */\n            alert_num = (error_code <= SSL_X509_OFFSET) ?  \n                SSL_ALERT_BAD_CERTIFICATE : SSL_ALERT_UNEXPECTED_MESSAGE;\n            break;\n    }\n\n    buf[0] = is_warning ? 1 : 2;\n    buf[1] = alert_num;\n    send_packet(ssl, PT_ALERT_PROTOCOL, buf, sizeof(buf));\n    //DISPLAY_ALERT(ssl, alert_num);\n    return is_warning ? 0 : 1;\n}\n\n/**\n * Process a client finished message.\n */\nint ICACHE_FLASH_ATTR process_finished(SSL *ssl, uint8_t *buf, int hs_len)\n{\n    int ret = SSL_OK;\n    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);\n    int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME);\n\n    PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE+4);\n\n    /* check that we all work before we continue */\n    if (os_memcmp(ssl->dc->final_finish_mac, &buf[4], SSL_FINISHED_HASH_SIZE))\n        return SSL_ERROR_FINISHED_INVALID;\n\n    if ((!is_client && !resume) || (is_client && resume))\n    {\n        if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)\n            ret = send_finished(ssl);\n    }\n\n    /* if we ever renegotiate */\n    ssl->next_state = is_client ? HS_HELLO_REQUEST : HS_CLIENT_HELLO;  \n    ssl->hs_status = ret;  /* set the final handshake status */\n\nerror:\n    return ret;\n}\n\n/**\n * Send a certificate.\n */\nint ICACHE_FLASH_ATTR send_certificate(SSL *ssl)\n{\n    int i = 0;\n    uint8_t *buf = ssl->bm_data;\n    int offset = 7;\n    int chain_length;\n\n    buf[0] = HS_CERTIFICATE;\n    buf[1] = 0;\n    buf[4] = 0;\n\n    while (i < ssl->ssl_ctx->chain_length)\n    {\n        SSL_CERT *cert = &ssl->ssl_ctx->certs[i];\n        buf[offset++] = 0;        \n        buf[offset++] = cert->size >> 8;        /* cert 1 length */\n        buf[offset++] = cert->size & 0xff;\n        os_memcpy(&buf[offset], cert->buf, cert->size);\n        offset += cert->size;\n        i++;\n    }\n\n    chain_length = offset - 7;\n    buf[5] = chain_length >> 8;        /* cert chain length */\n    buf[6] = chain_length & 0xff;\n    chain_length += 3;\n    buf[2] = chain_length >> 8;        /* handshake length */\n    buf[3] = chain_length & 0xff;\n    ssl->bm_index = offset;\n    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);\n}\n\n/**\n * Create a blob of memory that we'll get rid of once the handshake is\n * complete.\n */\nvoid ICACHE_FLASH_ATTR disposable_new(SSL *ssl)\n{\n    if (ssl->dc == NULL)\n    {\n        ssl->dc = (DISPOSABLE_CTX *)os_zalloc(sizeof(DISPOSABLE_CTX));\n        MD5_Init(&ssl->dc->md5_ctx);\n        SHA1_Init(&ssl->dc->sha1_ctx);\n    }\n}\n\n/**\n * Remove the temporary blob of memory.\n */\nvoid ICACHE_FLASH_ATTR disposable_free(SSL *ssl)\n{\n    if (ssl->dc)\n    {\n        os_free(ssl->dc->key_block);\n        os_memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX));\n        os_free(ssl->dc);\n        ssl->dc = NULL;\n    }\n\n}\n\n#ifndef CONFIG_SSL_SKELETON_MODE     /* no session resumption in this mode */\n/**\n * Find if an existing session has the same session id. If so, use the\n * master secret from this session for session resumption.\n */\nSSL_SESSION *ICACHE_FLASH_ATTR ssl_session_update(int max_sessions, SSL_SESSION *ssl_sessions[], \n        SSL *ssl, const uint8_t *session_id)\n{\n    time_t tm = 0;  //time(NULL);   wujg\n    time_t oldest_sess_time = tm;\n    SSL_SESSION *oldest_sess = NULL;\n    int i;\n\n    /* no sessions? Then bail */\n    if (max_sessions == 0)\n        return NULL;\n\n    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);\n    if (session_id)\n    {\n        for (i = 0; i < max_sessions; i++)\n        {\n            if (ssl_sessions[i])\n            {\n                /* kill off any expired sessions (including those in \n                   the future) */\n                if ((tm > ssl_sessions[i]->conn_time + SSL_EXPIRY_TIME) ||\n                            (tm < ssl_sessions[i]->conn_time))\n                {\n                    session_free(ssl_sessions, i);\n                    continue;\n                }\n\n                /* if the session id matches, it must still be less than \n                   the expiry time */\n                if (os_memcmp(ssl_sessions[i]->session_id, session_id,\n                                                SSL_SESSION_ID_SIZE) == 0)\n                {\n                    ssl->session_index = i;\n                    os_memcpy(ssl->dc->master_secret, \n                            ssl_sessions[i]->master_secret, SSL_SECRET_SIZE);\n                    SET_SSL_FLAG(SSL_SESSION_RESUME);\n                    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n                    return ssl_sessions[i];  /* a session was found */\n                }\n            }\n        }\n    }\n\n    /* If we've got here, no matching session was found - so create one */\n    for (i = 0; i < max_sessions; i++)\n    {\n        if (ssl_sessions[i] == NULL)\n        {\n            /* perfect, this will do */\n            ssl_sessions[i] = (SSL_SESSION *)os_zalloc(sizeof(SSL_SESSION));\n            ssl_sessions[i]->conn_time = tm;\n            ssl->session_index = i;\n            SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n            return ssl_sessions[i]; /* return the session object */\n        }\n        else if (ssl_sessions[i]->conn_time <= oldest_sess_time)\n        {\n            /* find the oldest session */\n            oldest_sess_time = ssl_sessions[i]->conn_time;\n            oldest_sess = ssl_sessions[i];\n            ssl->session_index = i;\n        }\n    }\n\n    /* ok, we've used up all of our sessions. So blow the oldest session away */\n    oldest_sess->conn_time = tm;\n    os_memset(oldest_sess->session_id, 0, sizeof(SSL_SESSION_ID_SIZE));\n    os_memset(oldest_sess->master_secret, 0, sizeof(SSL_SECRET_SIZE));\n    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n    return oldest_sess;\n}\n\n/**\n * Free an existing session.\n */\nstatic void ICACHE_FLASH_ATTR session_free(SSL_SESSION *ssl_sessions[], int sess_index)\n{\n    if (ssl_sessions[sess_index])\n    {\n        os_free(ssl_sessions[sess_index]);\n        ssl_sessions[sess_index] = NULL;\n    }\n}\n\n/**\n * This ssl object doesn't want this session anymore.\n */\nvoid ICACHE_FLASH_ATTR kill_ssl_session(SSL_SESSION **ssl_sessions, SSL *ssl)\n{\n    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);\n\n    if (ssl->ssl_ctx->num_sessions)\n    {\n        session_free(ssl_sessions, ssl->session_index);\n        ssl->session = NULL;\n    }\n\n    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n}\n#endif /* CONFIG_SSL_SKELETON_MODE */\n\n/*\n * Get the session id for a handshake. This will be a 32 byte sequence.\n */\nEXP_FUNC const uint8_t * STDCALL ICACHE_FLASH_ATTR ssl_get_session_id(const SSL *ssl)\n{\n    return ssl->session_id;\n}\n\n/*\n * Get the session id size for a handshake. \n */\nEXP_FUNC uint8_t STDCALL ICACHE_FLASH_ATTR ssl_get_session_id_size(const SSL *ssl)\n{\n    return ssl->sess_id_size;\n}\n\n/*\n * Return the cipher id (in the SSL form).\n */\nEXP_FUNC uint8_t STDCALL ICACHE_FLASH_ATTR ssl_get_cipher_id(const SSL *ssl)\n{\n    return ssl->cipher;\n}\n\n/*\n * Return the status of the handshake.\n */\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_handshake_status(const SSL *ssl)\n{\n    return ssl->hs_status;\n}\n\n/*\n * Retrieve various parameters about the SSL engine.\n */\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_get_config(int offset)\n{\n    switch (offset)\n    {\n        /* return the appropriate build mode */\n        case SSL_BUILD_MODE:\n#if defined(CONFIG_SSL_FULL_MODE)\n            return SSL_BUILD_FULL_MODE;\n#elif defined(CONFIG_SSL_ENABLE_CLIENT)\n            return SSL_BUILD_ENABLE_CLIENT;\n#elif defined(CONFIG_ENABLE_VERIFICATION)\n            return SSL_BUILD_ENABLE_VERIFICATION;\n#elif defined(CONFIG_SSL_SERVER_ONLY )\n            return SSL_BUILD_SERVER_ONLY;\n#else \n            return SSL_BUILD_SKELETON_MODE;\n#endif\n\n        case SSL_MAX_CERT_CFG_OFFSET:\n            return CONFIG_SSL_MAX_CERTS;\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n        case SSL_MAX_CA_CERT_CFG_OFFSET:\n            return CONFIG_X509_MAX_CA_CERTS;\n#endif\n#ifdef CONFIG_SSL_HAS_PEM\n        case SSL_HAS_PEM:\n            return 1;\n#endif\n        default:\n            return 0;\n    }\n}\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n/**\n * Authenticate a received certificate.\n */\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_verify_cert(const SSL *ssl)\n{\n    int ret;\n    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);\n    ret = x509_verify(ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);\n    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n\n    if (ret)        /* modify into an SSL error type */\n    {\n        ret = SSL_X509_ERROR(ret);\n    }\n\n    return ret;\n}\n\n/**\n * Process a certificate message.\n */\nint ICACHE_FLASH_ATTR process_certificate(SSL *ssl, X509_CTX **x509_ctx)\n{\n    int ret = SSL_OK;\n    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];\n    int pkt_size = ssl->bm_index;\n    int cert_size, offset = 5;\n    int total_cert_size = (buf[offset]<<8) + buf[offset+1];\n    int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT);\n    X509_CTX **chain = x509_ctx;\n    offset += 2;\n\t\n    PARANOIA_CHECK(total_cert_size, offset);\n\n    while (offset < total_cert_size)\n    {\n        offset++;       /* skip empty char */\n        cert_size = (buf[offset]<<8) + buf[offset+1];\n        offset += 2;\n        \n        if (x509_new(&buf[offset], NULL, chain))\n        {\n            ret = SSL_ERROR_BAD_CERTIFICATE;\n            goto error;\n        }\n\n        chain = &((*chain)->next);\n        offset += cert_size;\n    }\n\t\n    PARANOIA_CHECK(pkt_size, offset);\n\n    /* if we are client we can do the verify now or later */\n    if (is_client && !IS_SET_SSL_FLAG(SSL_SERVER_VERIFY_LATER))\n    {\n        ret = ssl_verify_cert(ssl);\n    }\n\n    ssl->next_state = is_client ? HS_SERVER_HELLO_DONE : HS_CLIENT_KEY_XCHG;\n    ssl->dc->bm_proc_index += offset;\nerror:\n    return ret;\n}\n\n#endif /* CONFIG_SSL_CERT_VERIFICATION */\n\n/**\n * Debugging routine to display SSL handshaking stuff.\n */\n#ifdef CONFIG_SSL_FULL_MODE\n/**\n * Debugging routine to display SSL states.\n */\n#if 0\nvoid ICACHE_FLASH_ATTR DISPLAY_STATE(SSL *ssl, int is_send, uint8_t state, int not_ok)\n{\n    const char *str;\n\n    if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))\n        return;\n\n    ssl_printf(not_ok ? \"Error - invalid State:\\t\" : \"State:\\t\");\n    ssl_printf(is_send ? \"sending \" : \"receiving \");\n\n    switch (state)\n    {\n        case HS_HELLO_REQUEST:\n            str = \"Hello Request (0)\";\n            break;\n\n        case HS_CLIENT_HELLO:\n            str = \"Client Hello (1)\";\n            break;\n\n        case HS_SERVER_HELLO:\n            str = \"Server Hello (2)\";\n            break;\n\n        case HS_CERTIFICATE:\n            str = \"Certificate (11)\";\n            break;\n\n        case HS_SERVER_KEY_XCHG:\n            str = \"Certificate Request (12)\";\n            break;\n\n        case HS_CERT_REQ:\n            str = \"Certificate Request (13)\";\n            break;\n\n        case HS_SERVER_HELLO_DONE:\n            str = \"Server Hello Done (14)\";\n            break;\n\n        case HS_CERT_VERIFY:\n            str = \"Certificate Verify (15)\";\n            break;\n\n        case HS_CLIENT_KEY_XCHG:\n            str = \"Client Key Exchange (16)\";\n            break;\n\n        case HS_FINISHED:\n            str = \"Finished (16)\";\n            break;\n\n        default:\n            str = \"Error (Unknown)\";\n            \n            break;\n    }\n\n    ssl_printf(\"%s\\n\", str);\n    //TTY_FLUSH();\n}\n\n/**\n * Debugging routine to display RSA objects\n */\nvoid ICACHE_FLASH_ATTR DISPLAY_RSA(SSL *ssl, const RSA_CTX *rsa_ctx)\n{\n    if (!IS_SET_SSL_FLAG(SSL_DISPLAY_RSA))\n        return;\n\n    RSA_print(rsa_ctx);\n    //TTY_FLUSH();\n}\n\n/**\n * Debugging routine to display SSL handshaking bytes.\n */\nvoid ICACHE_FLASH_ATTR DISPLAY_BYTES(SSL *ssl, const char *format, \n        const uint8_t *data, int size, ...)\n{\n// wujg : pass compile first\n//    va_list(ap);\n\n//    if (!IS_SET_SSL_FLAG(SSL_DISPLAY_BYTES))\n//        return;\n\n//    va_start(ap, size);\n//    print_blob(format, data, size, va_arg(ap, char *));\n//    va_end(ap);\n//    TTY_FLUSH();\n}\n\n/**\n * Debugging routine to display SSL handshaking errors.\n */\nEXP_FUNC void STDCALL ICACHE_FLASH_ATTR ssl_display_error(int error_code)\n{\n    if (error_code == SSL_OK)\n        return;\n\n    ssl_printf(\"Error: \");\n\n    /* X509 error? */\n    if (error_code < SSL_X509_OFFSET)\n    {\n        ssl_printf(\"%s\\n\", x509_display_error(error_code - SSL_X509_OFFSET));\n        return;\n    }\n\n    /* SSL alert error code */\n    if (error_code > SSL_ERROR_CONN_LOST)\n    {\n        ssl_printf(\"SSL error %d\\n\", -error_code);\n        return;\n    }\n\n    switch (error_code)\n    {\n        case SSL_ERROR_DEAD:\n            ssl_printf(\"connection dead\");\n            break;\n\n        case SSL_ERROR_INVALID_HANDSHAKE:\n            ssl_printf(\"invalid handshake\");\n            break;\n\n        case SSL_ERROR_INVALID_PROT_MSG:\n            ssl_printf(\"invalid protocol message\");\n            break;\n\n        case SSL_ERROR_INVALID_HMAC:\n            ssl_printf(\"invalid mac\");\n            break;\n\n        case SSL_ERROR_INVALID_VERSION:\n            ssl_printf(\"invalid version\");\n            break;\n\n        case SSL_ERROR_INVALID_SESSION:\n            ssl_printf(\"invalid session\");\n            break;\n\n        case SSL_ERROR_NO_CIPHER:\n            ssl_printf(\"no cipher\");\n            break;\n\n        case SSL_ERROR_CONN_LOST:\n            ssl_printf(\"connection lost\");\n            break;\n\n        case SSL_ERROR_BAD_CERTIFICATE:\n            ssl_printf(\"bad certificate\");\n            break;\n\n        case SSL_ERROR_INVALID_KEY:\n            ssl_printf(\"invalid key\");\n            break;\n\n        case SSL_ERROR_FINISHED_INVALID:\n            ssl_printf(\"finished invalid\");\n            break;\n\n        case SSL_ERROR_NO_CERT_DEFINED:\n            ssl_printf(\"no certificate defined\");\n            break;\n\n        case SSL_ERROR_NO_CLIENT_RENOG:\n            ssl_printf(\"client renegotiation not supported\");\n            break;\n            \n        case SSL_ERROR_NOT_SUPPORTED:\n            ssl_printf(\"Option not supported\");\n            break;\n\n        default:\n            ssl_printf(\"undefined as yet - %d\", error_code);\n            break;\n    }\n\n    ssl_printf(\"\\n\");\n    //TTY_FLUSH();\n}\n\n/**\n * Debugging routine to display alerts.\n */\nvoid ICACHE_FLASH_ATTR DISPLAY_ALERT(SSL *ssl, int alert)\n{\n    if (!IS_SET_SSL_FLAG(SSL_DISPLAY_STATES))\n        return;\n\n    ssl_printf(\"Alert: \");\n\n    switch (alert)\n    {\n        case SSL_ALERT_CLOSE_NOTIFY:\n            ssl_printf(\"close notify\");\n            break;\n\n        case SSL_ALERT_INVALID_VERSION:\n            ssl_printf(\"invalid version\");\n            break;\n\n        case SSL_ALERT_BAD_CERTIFICATE:\n            ssl_printf(\"bad certificate\");\n            break;\n\n        case SSL_ALERT_UNEXPECTED_MESSAGE:\n            ssl_printf(\"unexpected message\");\n            break;\n\n        case SSL_ALERT_BAD_RECORD_MAC:\n            ssl_printf(\"bad record mac\");\n            break;\n\n        case SSL_ALERT_HANDSHAKE_FAILURE:\n            ssl_printf(\"handshake failure\");\n            break;\n\n        case SSL_ALERT_ILLEGAL_PARAMETER:\n            ssl_printf(\"illegal parameter\");\n            break;\n\n        case SSL_ALERT_DECODE_ERROR:\n            ssl_printf(\"decode error\");\n            break;\n\n        case SSL_ALERT_DECRYPT_ERROR:\n            ssl_printf(\"decrypt error\");\n            break;\n\n        case SSL_ALERT_NO_RENEGOTIATION:\n            ssl_printf(\"no renegotiation\");\n            break;\n\n        default:\n            ssl_printf(\"alert - (unknown %d)\", alert);\n            break;\n    }\n\n    ssl_printf(\"\\n\");\n    //TTY_FLUSH();\n}\n#endif\n#endif /* CONFIG_SSL_FULL_MODE */\n\n/**\n * Return the version of this library.\n */\nEXP_FUNC const char  * STDCALL ICACHE_FLASH_ATTR ssl_version()\n{\n    static const char * axtls_version = AXTLS_VERSION;\n    return axtls_version;\n}\n\n/**\n * Enable the various language bindings to work regardless of the\n * configuration - they just return an error statement and a bad return code.\n */\n#if !defined(CONFIG_SSL_FULL_MODE)\nEXP_FUNC void STDCALL ssl_display_error(int error_code) {}\n#endif\n\n#ifdef CONFIG_BINDINGS\n#if !defined(CONFIG_SSL_ENABLE_CLIENT)\nEXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const\n        uint8_t *session_id, uint8_t sess_id_size)\n{\n    ssl_printf(unsupported_str);\n    return NULL;\n}\n#endif\n\n#if !defined(CONFIG_SSL_CERT_VERIFICATION)\nEXP_FUNC int STDCALL ICACHE_FLASH_ATTR ssl_verify_cert(const SSL *ssl)\n{\n    ssl_printf(unsupported_str);\n    return -1;\n}\n\n\nEXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_get_cert_dn(const SSL *ssl, int component)\n{\n    ssl_printf(unsupported_str);\n    return NULL;\n}\n\nEXP_FUNC const char * STDCALL ICACHE_FLASH_ATTR ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index)\n{\n    ssl_printf(unsupported_str);\n    return NULL;\n}\n\n#endif  /* CONFIG_SSL_CERT_VERIFICATION */\n\n#endif /* CONFIG_BINDINGS */\n\n"
  },
  {
    "path": "app/ssl/ssl/ssl_tls1_clnt.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n//#include <stdlib.h>\n//#include <string.h>\n//#include <time.h>\n//#include <stdio.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_ssl.h\"\n#include \"lwip/tcp.h\"\n#include \"ssl/app/espconn_ssl.h\"\n\n#ifdef CONFIG_SSL_ENABLE_CLIENT        /* all commented out if no client */\n\nstatic int send_client_hello(SSL *ssl);\nstatic int process_server_hello(SSL *ssl);\nstatic int process_server_hello_done(SSL *ssl);\nstatic int send_client_key_xchg(SSL *ssl);\nstatic int process_cert_req(SSL *ssl);\nstatic int send_cert_verify(SSL *ssl);\n\n#if 0\n/*\n * Establish a new SSL connection to an SSL server.\n */\nEXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const\n        uint8_t *session_id, uint8_t sess_id_size)\n{\n    SSL *ssl = ssl_new(ssl_ctx, client_fd);\n    ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */\n\n    if (session_id && ssl_ctx->num_sessions)\n    {\n        if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */\n        {\n            ssl_free(ssl);\n            return NULL;\n        }\n\n        os_memcpy(ssl->session_id, session_id, sess_id_size);\n        ssl->sess_id_size = sess_id_size;\n        SET_SSL_FLAG(SSL_SESSION_RESUME);   /* just flag for later */\n    }\n\n    SET_SSL_FLAG(SSL_IS_CLIENT);\n    do_client_connect(ssl);\n    return ssl;\n}\n#endif\n\n/*\n * Establish a new SSL connection to an SSL server.(raw api)add by ives 12.12.2013\n */\nEXP_FUNC SSL *STDCALL ICACHE_FLASH_ATTR SSLClient_new(SSL_CTX *ssl_ctx, struct tcp_pcb *SslClient_pcb, const\n        uint8_t *session_id, uint8_t sess_id_size)\n{\t\n    SSL *ssl = ssl_new_context(ssl_ctx, SslClient_pcb);\n    ssl->version = SSL_PROTOCOL_VERSION_MAX;\n    if (session_id && ssl_ctx->num_sessions) {\n        if (sess_id_size > SSL_SESSION_ID_SIZE) {\n            ssl_free(ssl);\n            return NULL;\n        }\n        os_memcpy(ssl->session_id, session_id, sess_id_size);\n        ssl->sess_id_size = sess_id_size;\n        SET_SSL_FLAG(SSL_SESSION_RESUME);\n    }\n    SET_SSL_FLAG(SSL_IS_CLIENT);\n    do_client_connect(ssl);\n    return ssl;\n}\n/*\n * Process the handshake record.\n */\nint ICACHE_FLASH_ATTR do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)\n{\n    int ret;\n\n    /* To get here the state must be valid */\n//\tssl_printf(\"do_clnt_handshake: %d %d\\n\",__LINE__, handshake_type);\n    switch (handshake_type)\n    {\n        case HS_SERVER_HELLO:\n            ret = process_server_hello(ssl);\n            break;\n\n        case HS_CERTIFICATE:\n            ret = process_certificate(ssl, &ssl->x509_ctx);\n            break;\n\n        case HS_SERVER_HELLO_DONE:\n            if ((ret = process_server_hello_done(ssl)) == SSL_OK)\n            {\n                if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ))\n                {\n                    if ((ret = send_certificate(ssl)) == SSL_OK &&\n                        (ret = send_client_key_xchg(ssl)) == SSL_OK)\n                    {\n                        send_cert_verify(ssl);\n                    }\n                }\n                else\n                {\n                    ret = send_client_key_xchg(ssl);\n                }\n\n                if (ret == SSL_OK && \n                     (ret = send_change_cipher_spec(ssl)) == SSL_OK)\n                {\n                    ret = send_finished(ssl);\n                }\n            }\n            break;\n\n        case HS_CERT_REQ:\n            ret = process_cert_req(ssl);\n            break;\n\n        case HS_FINISHED:\n            ret = process_finished(ssl, buf, hs_len);\n            disposable_free(ssl);   /* free up some memory */\n            /* note: client renegotiation is not allowed after this */\n            break;\n\n        case HS_HELLO_REQUEST:\n            disposable_new(ssl);\n            ret = do_client_connect(ssl);\n            break;\n\n        default:\n            ret = SSL_ERROR_INVALID_HANDSHAKE;\n            break;\n    }\n\n    return ret;\n}\n\n/*\n * Do the handshaking from the beginning.\n */\nint ICACHE_FLASH_ATTR do_client_connect(SSL *ssl)\n{\n    int ret = SSL_OK;\n\t\n    send_client_hello(ssl);                 /* send the client hello */\n    ssl->bm_read_index = 0;\n    ssl->next_state = HS_SERVER_HELLO;\n    ssl->hs_status = SSL_NOT_OK;            /* not connected */\n#if 0\n    /* sit in a loop until it all looks good */\n    if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS))\n    {\n        while (ssl->hs_status != SSL_OK)\n        {\n            ret = ssl_read(ssl, NULL);\n            ssl_printf(\"%s %d %d\\n\", __func__, __LINE__,ret);\n            if (ret < SSL_OK)\n                break;\n        }\n\n        ssl->hs_status = ret;            /* connected? */    \n    }\n#endif\n    return ret;\n}\n\n/*\n * Send the initial client hello.\n */\nstatic int ICACHE_FLASH_ATTR send_client_hello(SSL *ssl)\n{\n    uint8_t *buf = ssl->bm_data;\n    time_t tm = 0;  //time(NULL); wujg : pass compile first\n    uint8_t *tm_ptr = &buf[6]; /* time will go here */\n    int i, offset;\n\n    buf[0] = HS_CLIENT_HELLO;\n    buf[1] = 0;\n    buf[2] = 0;\n    /* byte 3 is calculated later */\n    buf[4] = 0x03;\n    buf[5] = ssl->version & 0x0f;\n\n    /* client random value - spec says that 1st 4 bytes are big endian time */\n    *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24);\n    *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16);\n    *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8);\n    *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff));\n    get_random(SSL_RANDOM_SIZE-4, &buf[10]);\n    os_memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);\n    offset = 6 + SSL_RANDOM_SIZE;\n\n    /* give session resumption a go */\n    if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))    /* set initially by user */\n    {\n        buf[offset++] = ssl->sess_id_size;\n        os_memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size);\n        offset += ssl->sess_id_size;\n        CLR_SSL_FLAG(SSL_SESSION_RESUME);       /* clear so we can set later */\n    }\n    else\n    {\n        /* no session id - because no session resumption just yet */\n        buf[offset++] = 0;\n    }\n\n    buf[offset++] = 0;              /* number of ciphers */\n    buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */\n\n    /* put all our supported protocols in our request */\n    for (i = 0; i < NUM_PROTOCOLS; i++)\n    {\n        buf[offset++] = 0;          /* cipher we are using */\n        buf[offset++] = ssl_prot_prefs[i];\n    }\n\n    buf[offset++] = 1;              /* no compression */\n    buf[offset++] = 0;\n    buf[3] = offset - 4;            /* handshake size */\n\n    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);\n}\n\n/*\n * Process the server hello.\n */\nstatic int ICACHE_FLASH_ATTR process_server_hello(SSL *ssl)\n{\n    uint8_t *buf = ssl->bm_data;\n    int pkt_size = ssl->bm_index;\n    int num_sessions = ssl->ssl_ctx->num_sessions;\n    uint8_t sess_id_size;\n    int offset, ret = SSL_OK;\n\n    /* check that we are talking to a TLSv1 server */\n    uint8_t version = (buf[4] << 4) + buf[5];\n    if (version > SSL_PROTOCOL_VERSION_MAX)\n    {\n        version = SSL_PROTOCOL_VERSION_MAX;\n    }\n    else if (ssl->version < SSL_PROTOCOL_MIN_VERSION)\n    {\n        ret = SSL_ERROR_INVALID_VERSION;\n        //ssl_display_error(ret);\n        goto error;\n    }\n\n    ssl->version = version;\n\n    /* get the server random value */\n    os_memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);\n    offset = 6 + SSL_RANDOM_SIZE; /* skip of session id size */\n    sess_id_size = buf[offset++];\n\n    if (sess_id_size > SSL_SESSION_ID_SIZE)\n    {\n        ret = SSL_ERROR_INVALID_SESSION;\n        goto error;\n    }\n\n    if (num_sessions)\n    {\n        ssl->session = ssl_session_update(num_sessions,\n                ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]);\n        os_memcpy(ssl->session->session_id, &buf[offset], sess_id_size);\n\n        /* pad the rest with 0's */\n        if (sess_id_size < SSL_SESSION_ID_SIZE)\n        {\n            os_memset(&ssl->session->session_id[sess_id_size], 0,\n                SSL_SESSION_ID_SIZE-sess_id_size);\n        }\n    }\n\n    os_memcpy(ssl->session_id, &buf[offset], sess_id_size);\n    ssl->sess_id_size = sess_id_size;\n    offset += sess_id_size;\n\n    /* get the real cipher we are using */\n    ssl->cipher = buf[++offset];\n    ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ? \n                                        HS_FINISHED : HS_CERTIFICATE;\n\n    offset++;   // skip the compr\n    PARANOIA_CHECK(pkt_size, offset);\n    ssl->dc->bm_proc_index = offset+1; \n\nerror:\n    return ret;\n}\n\n/**\n * Process the server hello done message.\n */\nstatic int ICACHE_FLASH_ATTR process_server_hello_done(SSL *ssl)\n{\n    ssl->next_state = HS_FINISHED;\n    return SSL_OK;\n}\n\n/*\n * Send a client key exchange message.\n */\nstatic int ICACHE_FLASH_ATTR send_client_key_xchg(SSL *ssl)\n{\n    uint8_t *buf = ssl->bm_data;\n    uint8_t premaster_secret[SSL_SECRET_SIZE];\n    int enc_secret_size = -1;\n\n    buf[0] = HS_CLIENT_KEY_XCHG;\n    buf[1] = 0;\n\n    premaster_secret[0] = 0x03; /* encode the version number */\n    premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */\n    get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]);\n    //DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx);\n\n    /* rsa_ctx->bi_ctx is not thread-safe */\n    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);\n    enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret,\n            SSL_SECRET_SIZE, &buf[6], 0);\n    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n\n    buf[2] = (enc_secret_size + 2) >> 8;\n    buf[3] = (enc_secret_size + 2) & 0xff;\n    buf[4] = enc_secret_size >> 8;\n    buf[5] = enc_secret_size & 0xff;\n\n    generate_master_secret(ssl, premaster_secret);\n    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6);\n}\n\n/*\n * Process the certificate request.\n */\nstatic int ICACHE_FLASH_ATTR process_cert_req(SSL *ssl)\n{\n    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];\n    int ret = SSL_OK;\n    int offset = (buf[2] << 4) + buf[3];\n    int pkt_size = ssl->bm_index;\n\n    /* don't do any processing - we will send back an RSA certificate anyway */\n    ssl->next_state = HS_SERVER_HELLO_DONE;\n    SET_SSL_FLAG(SSL_HAS_CERT_REQ);\n    ssl->dc->bm_proc_index += offset;\n    PARANOIA_CHECK(pkt_size, offset);\nerror:\n    return ret;\n}\n\n/*\n * Send a certificate verify message.\n */\nstatic int ICACHE_FLASH_ATTR send_cert_verify(SSL *ssl)\n{\n    uint8_t *buf = ssl->bm_data;\n    uint8_t dgst[MD5_SIZE+SHA1_SIZE];\n    RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;\n    int n = 0, ret;\n\n    //DISPLAY_RSA(ssl, rsa_ctx);\n\n    buf[0] = HS_CERT_VERIFY;\n    buf[1] = 0;\n\n    finished_digest(ssl, NULL, dgst);   /* calculate the digest */\n\n    /* rsa_ctx->bi_ctx is not thread-safe */\n    if (rsa_ctx)\n    {\n        SSL_CTX_LOCK(ssl->ssl_ctx->mutex);\n        n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1);\n        SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n\n        if (n == 0)\n        {\n            ret = SSL_ERROR_INVALID_KEY;\n            goto error;\n        }\n    }\n    \n    buf[4] = n >> 8;        /* add the RSA size (not officially documented) */\n    buf[5] = n & 0xff;\n    n += 2;\n    buf[2] = n >> 8;\n    buf[3] = n & 0xff;\n    ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4);\n\nerror:\n    return ret;\n}\n\n#endif      /* CONFIG_SSL_ENABLE_CLIENT */\n"
  },
  {
    "path": "app/ssl/ssl/ssl_tls1_svr.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n//#include <stdlib.h>\n//#include <string.h>\n//#include <stdio.h>\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_ssl.h\"\n//#include \"../httpd/axhttp.h\"\n#include \"ssl/app/espconn_ssl.h\"\n\nstatic const uint8_t g_hello_done[] = { HS_SERVER_HELLO_DONE, 0, 0, 0 };\n\nstatic int process_client_hello(SSL *ssl);\nstatic int send_server_hello_sequence(SSL *ssl);\nstatic int send_server_hello(SSL *ssl);\nstatic int send_server_hello_done(SSL *ssl);\nstatic int process_client_key_xchg(SSL *ssl);\n#ifdef CONFIG_SSL_CERT_VERIFICATION\nstatic int send_certificate_request(SSL *ssl);\nstatic int process_cert_verify(SSL *ssl);\n#endif\n\n#if 0\n/*\n * Establish a new SSL connection to an SSL client.\n */\nEXP_FUNC SSL * STDCALL ICACHE_FLASH_ATTR ssl_server_new(SSL_CTX *ssl_ctx, int client_fd)\n{\n    SSL *ssl;\n\n    ssl = ssl_new(ssl_ctx, client_fd);\n    ssl->next_state = HS_CLIENT_HELLO;\n\n#ifdef CONFIG_SSL_FULL_MODE\n    if (ssl_ctx->chain_length == 0)\n        ssl_printf(\"Warning - no server certificate defined\\n\"); TTY_FLUSH();\n#endif\n\n    return ssl;\n}\n#endif\n\n/*\n * Establish a new SSL connection to an SSL client.(raw api)add by ives 12.19.2013\n */\nEXP_FUNC SSL *STDCALL ICACHE_FLASH_ATTR sslserver_new(SSL_CTX *ssl_ctx, struct tcp_pcb* client_pcb)\n{\n    SSL *ssl;\n    ssl = ssl_new_context(ssl_ctx, client_pcb);\n    ssl->next_state = HS_CLIENT_HELLO;\n#ifdef CONFIG_SSL_FULL_MODE\n    if (ssl_ctx->chain_length == 0)\n        ssl_printf(\"Warning - no server certificate defined\\n\");\n    //TTY_FLUSH();\n#endif\n    return ssl;\n}\n/*\n * Process the handshake record.\n */\nint ICACHE_FLASH_ATTR do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)\n{\n    int ret = SSL_OK;\n    ssl->hs_status = SSL_NOT_OK;            /* not connected */\n\n    /* To get here the state must be valid */\n//\tssl_printf(\"%d %s %d\\n\",handshake_type, __func__, __LINE__);\n    switch (handshake_type)\n    {\n        case HS_CLIENT_HELLO:\n            if ((ret = process_client_hello(ssl)) == SSL_OK)\n                ret = send_server_hello_sequence(ssl);\n            break;\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n        case HS_CERTIFICATE:/* the client sends its cert */\n            ret = process_certificate(ssl, &ssl->x509_ctx);\n\n            if (ret == SSL_OK)    /* verify the cert */\n            { \n                int cert_res;\n                cert_res = x509_verify(\n                        ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx);\n                ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res);\n            }\n            break;\n\n        case HS_CERT_VERIFY:    \n            ret = process_cert_verify(ssl);\n            add_packet(ssl, buf, hs_len);   /* needs to be done after */\n            break;\n#endif\n        case HS_CLIENT_KEY_XCHG:\n            ret = process_client_key_xchg(ssl);\n            break;\n\n        case HS_FINISHED:\n            ret = process_finished(ssl, buf, hs_len);\n            disposable_free(ssl);   /* free up some memory */\n            break;\n    }\n\n    return ret;\n}\n\n/* \n * Process a client hello message.\n */\nstatic int ICACHE_FLASH_ATTR process_client_hello(SSL *ssl)\n{\n    uint8_t *buf = ssl->bm_data;\n    uint8_t *record_buf = ssl->hmac_header;\n    int pkt_size = ssl->bm_index;\n    int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE;\n    int ret = SSL_OK;\n    \n    uint8_t version = (buf[4] << 4) + buf[5];\n    ssl->version = ssl->client_version = version;\n\n    if (version > SSL_PROTOCOL_VERSION_MAX)\n    {\n        /* use client's version instead */\n        ssl->version = SSL_PROTOCOL_VERSION_MAX; \n    }\n    else if (version < SSL_PROTOCOL_MIN_VERSION)  /* old version supported? */\n    {\n        ret = SSL_ERROR_INVALID_VERSION;\n        //ssl_display_error(ret);\n        goto error;\n    }\n\n    os_memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);\n\n    /* process the session id */\n    id_len = buf[offset++];\n    if (id_len > SSL_SESSION_ID_SIZE)\n    {\n        return SSL_ERROR_INVALID_SESSION;\n    }\n\n#ifndef CONFIG_SSL_SKELETON_MODE\n    ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,\n            ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);\n#endif\n\n    offset += id_len;\n    cs_len = (buf[offset]<<8) + buf[offset+1];\n    offset += 2;        /* add 1 due to all cipher suites being 8 bit */\n\n    PARANOIA_CHECK(pkt_size, offset);\n\n    /* work out what cipher suite we are going to use - client defines \n       the preference */\n    for (i = 0; i < cs_len; i += 2)\n    {\n        for (j = 0; j < NUM_PROTOCOLS; j++)\n        {\n            if (ssl_prot_prefs[j] == ((buf[offset+i]<<8) + buf[offset+i+1]))   /* got a match? */\n            {\n                ssl->cipher = ssl_prot_prefs[j];\n                goto do_state;\n            }\n        }\n    }\n\n    /* ouch! protocol is not supported */\n    ret = SSL_ERROR_NO_CIPHER;\n\ndo_state:\nerror:\n    return ret;\n}\n\n#ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE\n/*\n * Some browsers use a hybrid SSLv2 \"client hello\" \n */\nint process_sslv23_client_hello(SSL *ssl)\n{\n    uint8_t *buf = ssl->bm_data;\n    int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1];\n    int ret = SSL_OK;\n\n    /* we have already read 3 extra bytes so far */\n//    int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3);\n\tint read_len = pbuf_copy_partial(ssl->ssl_pbuf, buf, bytes_needed - 3, 0);\n    int cs_len = buf[1];\n    int id_len = buf[3];\n    int ch_len = buf[5];\n    int i, j, offset = 8;   /* start at first cipher */\n    int random_offset = 0;\n\n    DISPLAY_BYTES(ssl, \"received %d bytes\", buf, read_len, read_len);\n    \n    add_packet(ssl, buf, read_len);\n\n    /* connection has gone, so die */\n    if (bytes_needed < 0)\n    {\n        return SSL_ERROR_CONN_LOST;\n    }\n\n    /* now work out what cipher suite we are going to use */\n    for (j = 0; j < NUM_PROTOCOLS; j++)\n    {\n        for (i = 0; i < cs_len; i += 3)\n        {\n            if (ssl_prot_prefs[j] == buf[offset+i])\n            {\n                ssl->cipher = ssl_prot_prefs[j];\n                goto server_hello;\n            }\n        }\n    }\n\n    /* ouch! protocol is not supported */\n    ret = SSL_ERROR_NO_CIPHER;\n    goto error;\n\nserver_hello:\n    /* get the session id */\n    offset += cs_len - 2;   /* we've gone 2 bytes past the end */\n#ifndef CONFIG_SSL_SKELETON_MODE\n    ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions,\n            ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL);\n#endif\n\n    /* get the client random data */\n    offset += id_len;\n\n    /* random can be anywhere between 16 and 32 bytes long - so it is padded\n     * with 0's to the left */\n    if (ch_len == 0x10)\n    {\n        random_offset += 0x10;\n    }\n\n    memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len);\n    ret = send_server_hello_sequence(ssl);\n\nerror:\n    return ret;\n}\n#endif\n\n/*\n * Send the entire server hello sequence\n */\nstatic int ICACHE_FLASH_ATTR send_server_hello_sequence(SSL *ssl)\n{\n    int ret;\n\n    if ((ret = send_server_hello(ssl)) == SSL_OK)\n    {\n#ifndef CONFIG_SSL_SKELETON_MODE\n        /* resume handshake? */\n        if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))\n        {\n            if ((ret = send_change_cipher_spec(ssl)) == SSL_OK)\n            {\n                ret = send_finished(ssl);\n                ssl->next_state = HS_FINISHED;\n            }\n        }\n        else \n#endif\n        if ((ret = send_certificate(ssl)) == SSL_OK)\n        {\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n            /* ask the client for its certificate */\n            if (IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION))\n            {\n                if ((ret = send_certificate_request(ssl)) == SSL_OK)\n                {\n                    ret = send_server_hello_done(ssl);\n                    ssl->next_state = HS_CERTIFICATE;\n                }\n            }\n            else\n#endif\n            {\n                ret = send_server_hello_done(ssl);\n                ssl->next_state = HS_CLIENT_KEY_XCHG;\n            }\n        }\n    }\n\n    return ret;\n}\n\n/*\n * Send a server hello message.\n */\nstatic int ICACHE_FLASH_ATTR send_server_hello(SSL *ssl)\n{\n    uint8_t *buf = ssl->bm_data;\n    int offset = 0;\n\n    buf[0] = HS_SERVER_HELLO;\n    buf[1] = 0;\n    buf[2] = 0;\n    /* byte 3 is calculated later */\n    buf[4] = 0x03;\n    buf[5] = ssl->version & 0x0f;\n\n    /* server random value */\n    get_random(SSL_RANDOM_SIZE, &buf[6]);\n    os_memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);\n    offset = 6 + SSL_RANDOM_SIZE;\n\n#ifndef CONFIG_SSL_SKELETON_MODE\n    if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME))\n    {\n        /* retrieve id from session cache */\n        buf[offset++] = SSL_SESSION_ID_SIZE;\n        os_memcpy(&buf[offset], ssl->session->session_id, SSL_SESSION_ID_SIZE);\n        os_memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE);\n        ssl->sess_id_size = SSL_SESSION_ID_SIZE;\n        offset += SSL_SESSION_ID_SIZE;\n    }\n    else    /* generate our own session id */\n#endif\n    {\n#ifndef CONFIG_SSL_SKELETON_MODE\n        buf[offset++] = SSL_SESSION_ID_SIZE;\n        get_random(SSL_SESSION_ID_SIZE, &buf[offset]);\n        os_memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE);\n        ssl->sess_id_size = SSL_SESSION_ID_SIZE;\n\n        /* store id in session cache */\n        if (ssl->ssl_ctx->num_sessions)\n        {\n            os_memcpy(ssl->session->session_id, \n                    ssl->session_id, SSL_SESSION_ID_SIZE);\n        }\n\n        offset += SSL_SESSION_ID_SIZE;\n#else\n        buf[offset++] = 0;  /* don't bother with session id in skelton mode */\n#endif\n    }\n\n    buf[offset++] = 0;      /* cipher we are using */\n    buf[offset++] = ssl->cipher;\n    buf[offset++] = 0;      /* no compression */\n    buf[3] = offset - 4;    /* handshake size */\n    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);\n}\n\n/*\n * Send the server hello done message.\n */\nstatic int ICACHE_FLASH_ATTR send_server_hello_done(SSL *ssl)\n{\n    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, \n                            g_hello_done, sizeof(g_hello_done));\n}\n\n/*\n * Pull apart a client key exchange message. Decrypt the pre-master key (using\n * our RSA private key) and then work out the master key. Initialise the\n * ciphers.\n */\nstatic int ICACHE_FLASH_ATTR process_client_key_xchg(SSL *ssl)\n{\n    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];\n    int pkt_size = ssl->bm_index;\n    int premaster_size, secret_length = (buf[2] << 8) + buf[3];\n    uint8_t premaster_secret[MAX_KEY_BYTE_SIZE];\n    RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;\n    int offset = 4;\n    int ret = SSL_OK;\n    \n    if (rsa_ctx == NULL)\n    {\n        ret = SSL_ERROR_NO_CERT_DEFINED;\n        goto error;\n    }\n\n    /* is there an extra size field? */\n    if ((secret_length - 2) == rsa_ctx->num_octets)\n        offset += 2;\n\n    PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset);\n\n    /* rsa_ctx->bi_ctx is not thread-safe */\n    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);\n    premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1);\n    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n\n    if (premaster_size != SSL_SECRET_SIZE || \n            premaster_secret[0] != 0x03 ||  /* must be the same as client\n                                               offered version */\n                premaster_secret[1] != (ssl->client_version & 0x0f))\n    {\n        /* guard against a Bleichenbacher attack */\n        get_random(SSL_SECRET_SIZE, premaster_secret);\n        /* and continue - will die eventually when checking the mac */\n    }\n\n#if 0\n    print_blob(\"pre-master\", premaster_secret, SSL_SECRET_SIZE);\n#endif\n\n    generate_master_secret(ssl, premaster_secret);\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n    ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ?  \n                                            HS_CERT_VERIFY : HS_FINISHED;\n#else\n    ssl->next_state = HS_FINISHED; \n#endif\n\n    ssl->dc->bm_proc_index += rsa_ctx->num_octets+offset;\nerror:\n    return ret;\n}\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\nstatic const uint8_t g_cert_request[] = { HS_CERT_REQ, 0, 0, 4, 1, 0, 0, 0 };\n\n/*\n * Send the certificate request message.\n */\nstatic int ICACHE_FLASH_ATTR send_certificate_request(SSL *ssl)\n{\n    return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, \n            g_cert_request, sizeof(g_cert_request));\n}\n\n/*\n * Ensure the client has the private key by first decrypting the packet and\n * then checking the packet digests.\n */\nstatic int ICACHE_FLASH_ATTR process_cert_verify(SSL *ssl)\n{\n    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];\n    int pkt_size = ssl->bm_index;\n    uint8_t dgst_buf[MAX_KEY_BYTE_SIZE];\n    uint8_t dgst[MD5_SIZE+SHA1_SIZE];\n    X509_CTX *x509_ctx = ssl->x509_ctx;\n    int ret = SSL_OK;\n    int n;\n\n    PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6);\n    //DISPLAY_RSA(ssl, x509_ctx->rsa_ctx);\n\n    /* rsa_ctx->bi_ctx is not thread-safe */\n    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);\n    n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0);\n    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);\n\n    if (n != SHA1_SIZE + MD5_SIZE)\n    {\n        ret = SSL_ERROR_INVALID_KEY;\n        goto end_cert_vfy;\n    }\n\n    finished_digest(ssl, NULL, dgst);       /* calculate the digest */\n    if (os_memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE))\n    {\n        ret = SSL_ERROR_INVALID_KEY;\n    }\n\nend_cert_vfy:\n    ssl->next_state = HS_FINISHED;\nerror:\n    return ret;\n}\n\n#endif\n"
  },
  {
    "path": "app/ssl/ssl/ssl_x509.c",
    "content": "/*\n * Copyright (c) 2007, Cameron Rich\n * \n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without \n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice, \n *   this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice, \n *   this list of conditions and the following disclaimer in the documentation \n *   and/or other materials provided with the distribution.\n * * Neither the name of the axTLS project nor the names of its contributors \n *   may be used to endorse or promote products derived from this software \n *   without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/**\n * @file x509.c\n * \n * Certificate processing.\n */\n\n//#include <stdio.h>\n//#include <stdlib.h>\n//#include <string.h>\n//#include <time.h>\n#include \"ssl/app/espconn_ssl.h\"\n\n#include \"ssl/ssl_os_port.h\"\n#include \"ssl/ssl_crypto_misc.h\"\n//#include \"os.h\"\n#include \"lwip/mem.h\"\n\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n/**\n * Retrieve the signature from a certificate.\n */\nstatic const uint8_t * ICACHE_FLASH_ATTR get_signature(const uint8_t *asn1_sig, int *len)\n{\n    int offset = 0;\n    const uint8_t *ptr = NULL;\n\n    if (asn1_next_obj(asn1_sig, &offset, ASN1_SEQUENCE) < 0 || \n            asn1_skip_obj(asn1_sig, &offset, ASN1_SEQUENCE))\n        goto end_get_sig;\n\n    if (asn1_sig[offset++] != ASN1_OCTET_STRING)\n        goto end_get_sig;\n    *len = get_asn1_length(asn1_sig, &offset);\n    ptr = &asn1_sig[offset];          /* all ok */\n\nend_get_sig:\n    return ptr;\n}\n\n#endif\n\n/**\n * Construct a new x509 object.\n * @return 0 if ok. < 0 if there was a problem.\n */\nint ICACHE_FLASH_ATTR x509_new(const uint8_t *cert, int *len, X509_CTX **ctx)\n{\n    int begin_tbs, end_tbs;\n    int ret = X509_NOT_OK, offset = 0, cert_size = 0;\n    X509_CTX *x509_ctx;\n    BI_CTX *bi_ctx;\n\n    *ctx = (X509_CTX *)os_zalloc(sizeof(X509_CTX));\n    x509_ctx = *ctx;\n\n    /* get the certificate size */\n    asn1_skip_obj(cert, &cert_size, ASN1_SEQUENCE); \n\n    if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)\n        goto end_cert;\n\n    begin_tbs = offset;         /* start of the tbs */\n    end_tbs = begin_tbs;        /* work out the end of the tbs */\n    asn1_skip_obj(cert, &end_tbs, ASN1_SEQUENCE);\n\n    if (asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)\n        goto end_cert;\n\n    if (cert[offset] == ASN1_EXPLICIT_TAG)   /* optional version */\n    {\n        if (asn1_version(cert, &offset, x509_ctx))\n            goto end_cert;\n    }\n\n    if (asn1_skip_obj(cert, &offset, ASN1_INTEGER) || /* serial number */ \n            asn1_next_obj(cert, &offset, ASN1_SEQUENCE) < 0)\n        goto end_cert;\n\n    /* make sure the signature is ok */\n    if (asn1_signature_type(cert, &offset, x509_ctx))\n    {\n        ret = X509_VFY_ERROR_UNSUPPORTED_DIGEST;\n        goto end_cert;\n    }\n\n    if (asn1_name(cert, &offset, x509_ctx->ca_cert_dn) || \n            asn1_validity(cert, &offset, x509_ctx) ||\n            asn1_name(cert, &offset, x509_ctx->cert_dn) ||\n            asn1_public_key(cert, &offset, x509_ctx))\n    {\n        goto end_cert;\n    }\n\n    bi_ctx = x509_ctx->rsa_ctx->bi_ctx;\n#ifdef CONFIG_SSL_CERT_VERIFICATION /* only care if doing verification */\n    /* use the appropriate signature algorithm (SHA1/MD5/MD2) */\n    if (x509_ctx->sig_type == SIG_TYPE_MD5)\n    {\n        MD5_CTX md5_ctx;\n        uint8_t md5_dgst[MD5_SIZE];\n        MD5_Init(&md5_ctx);\n        MD5_Update(&md5_ctx, &cert[begin_tbs], end_tbs-begin_tbs);\n        MD5_Final(md5_dgst, &md5_ctx);\n        x509_ctx->digest = bi_import(bi_ctx, md5_dgst, MD5_SIZE);\n    }\n    else if (x509_ctx->sig_type == SIG_TYPE_SHA1)\n    {\n        SHA1_CTX sha_ctx;\n        uint8_t sha_dgst[SHA1_SIZE];\n        SHA1_Init(&sha_ctx);\n        SHA1_Update(&sha_ctx, &cert[begin_tbs], end_tbs-begin_tbs);\n        SHA1_Final(sha_dgst, &sha_ctx);\n        x509_ctx->digest = bi_import(bi_ctx, sha_dgst, SHA1_SIZE);\n    }\n    else if (x509_ctx->sig_type == SIG_TYPE_MD2)\n    {\n        MD2_CTX md2_ctx;\n        uint8_t md2_dgst[MD2_SIZE];\n        MD2_Init(&md2_ctx);\n        MD2_Update(&md2_ctx, &cert[begin_tbs], end_tbs-begin_tbs);\n        MD2_Final(md2_dgst, &md2_ctx);\n        x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE);\n    }\n\n    if (cert[offset] == ASN1_V3_DATA)\n    {\n        int suboffset;\n\n        ++offset;\n        get_asn1_length(cert, &offset);\n\n        if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0)\n        {\n            if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0)\n            {\n                int altlen;\n\n                if ((altlen = asn1_next_obj(cert, \n                                            &suboffset, ASN1_SEQUENCE)) > 0)\n                {\n                    int endalt = suboffset + altlen;\n                    int totalnames = 0;\n\n                    while (suboffset < endalt)\n                    {\n                        int type = cert[suboffset++];\n                        int dnslen = get_asn1_length(cert, &suboffset);\n\n                        if (type == ASN1_CONTEXT_DNSNAME)\n                        {\n                            x509_ctx->subject_alt_dnsnames = (char**)\n                                    os_realloc(x509_ctx->subject_alt_dnsnames, \n                                       (totalnames + 2) * sizeof(char*));\n                            x509_ctx->subject_alt_dnsnames[totalnames] = \n                                    (char*)os_malloc(dnslen + 1);\n                            x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL;\n                            os_memcpy(x509_ctx->subject_alt_dnsnames[totalnames], \n                                    cert + suboffset, dnslen);\n                            x509_ctx->subject_alt_dnsnames[\n                                    totalnames][dnslen] = 0;\n                            ++totalnames;\n                        }\n\n                        suboffset += dnslen;\n                    }\n                }\n            }\n        }\n    }\n\n    offset = end_tbs;   /* skip the rest of v3 data */\n    if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || \n            asn1_signature(cert, &offset, x509_ctx))\n        goto end_cert;\n#endif\n    ret = X509_OK;\nend_cert:\n    if (len)\n    {\n        *len = cert_size;\n    }\n\n    if (ret)\n    {\n#ifdef CONFIG_SSL_FULL_MODE\n        ssl_printf(\"Error: Invalid X509 ASN.1 file (%s)\\n\",\n                        x509_display_error(ret));\n#endif\n        x509_free(x509_ctx);\n        *ctx = NULL;\n    }\n\n    return ret;\n}\n\n/**\n * Free an X.509 object's resources.\n */\nvoid ICACHE_FLASH_ATTR x509_free(X509_CTX *x509_ctx)\n{\n    X509_CTX *next;\n    int i;\n\n    if (x509_ctx == NULL)       /* if already null, then don't bother */\n        return;\n\n    for (i = 0; i < X509_NUM_DN_TYPES; i++)\n    {\n        os_free(x509_ctx->ca_cert_dn[i]);\n        os_free(x509_ctx->cert_dn[i]);\n    }\n\n    os_free(x509_ctx->signature);\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION \n    if (x509_ctx->digest)\n    {\n        bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest);\n    }\n\n    if (x509_ctx->subject_alt_dnsnames)\n    {\n        for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i)\n            os_free(x509_ctx->subject_alt_dnsnames[i]);\n\n        os_free(x509_ctx->subject_alt_dnsnames);\n    }\n#endif\n\n    RSA_free(x509_ctx->rsa_ctx);\n    next = x509_ctx->next;\n    os_free(x509_ctx);\n    x509_free(next);        /* clear the chain */\n}\n\n#ifdef CONFIG_SSL_CERT_VERIFICATION\n/**\n * Take a signature and decrypt it.\n */\nstatic bigint *ICACHE_FLASH_ATTR sig_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,\n        bigint *modulus, bigint *pub_exp)\n{\n    int i, size;\n    bigint *decrypted_bi, *dat_bi;\n    bigint *bir = NULL;\n    uint8_t *block = (uint8_t *)os_malloc(sig_len);\n\n    /* decrypt */\n    dat_bi = bi_import(ctx, sig, sig_len);\n    ctx->mod_offset = BIGINT_M_OFFSET;\n\n    /* convert to a normal block */\n    decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp);\n\n    bi_export(ctx, decrypted_bi, block, sig_len);\n    ctx->mod_offset = BIGINT_M_OFFSET;\n\n    i = 10; /* start at the first possible non-padded byte */\n    while (block[i++] && i < sig_len);\n    size = sig_len - i;\n\n    /* get only the bit we want */\n    if (size > 0)\n    {\n        int len;\n        const uint8_t *sig_ptr = get_signature(&block[i], &len);\n\n        if (sig_ptr)\n        {\n            bir = bi_import(ctx, sig_ptr, len);\n        }\n    }\n\n    /* save a few bytes of memory */\n    bi_clear_cache(ctx);\n\n    os_free(block);\n    return bir;\n}\n\n/**\n * Do some basic checks on the certificate chain.\n *\n * Certificate verification consists of a number of checks:\n * - The date of the certificate is after the start date.\n * - The date of the certificate is before the finish date.\n * - A root certificate exists in the certificate store.\n * - That the certificate(s) are not self-signed.\n * - The certificate chain is valid.\n * - The signature of the certificate is valid.\n */\nint ICACHE_FLASH_ATTR x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert) \n{\n    int ret = X509_OK, i = 0;\n    bigint *cert_sig;\n    X509_CTX *next_cert = NULL;\n    BI_CTX *ctx = NULL;\n    bigint *mod = NULL, *expn = NULL;\n    int match_ca_cert = 0;\n    struct timeval tv;\n    uint8_t is_self_signed = 0;\n\n    if (cert == NULL)\n    {\n        ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       \n        goto end_verify;\n    }\n\n    /* a self-signed certificate that is not in the CA store - use this \n       to check the signature */\n    if (asn1_compare_dn(cert->ca_cert_dn, cert->cert_dn) == 0)\n    {\n        is_self_signed = 1;\n        ctx = cert->rsa_ctx->bi_ctx;\n        mod = cert->rsa_ctx->m;\n        expn = cert->rsa_ctx->e;\n    }\n\n//    gettimeofday(&tv, NULL);\n\n    /* check the not before date */\n    if (tv.tv_sec < cert->not_before)\n    {\n        ret = X509_VFY_ERROR_NOT_YET_VALID;\n        goto end_verify;\n    }\n\n    /* check the not after date */\n    if (tv.tv_sec > cert->not_after)\n    {\n        ret = X509_VFY_ERROR_EXPIRED;\n        goto end_verify;\n    }\n\n    next_cert = cert->next;\n\n    /* last cert in the chain - look for a trusted cert */\n    if (next_cert == NULL)\n    {\n       if (ca_cert_ctx != NULL) \n       {\n            /* go thu the CA store */\n            while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i])\n            {\n                if (asn1_compare_dn(cert->ca_cert_dn,\n                                            ca_cert_ctx->cert[i]->cert_dn) == 0)\n                {\n                    /* use this CA certificate for signature verification */\n                    match_ca_cert = 1;\n                    ctx = ca_cert_ctx->cert[i]->rsa_ctx->bi_ctx;\n                    mod = ca_cert_ctx->cert[i]->rsa_ctx->m;\n                    expn = ca_cert_ctx->cert[i]->rsa_ctx->e;\n                    break;\n                }\n\n                i++;\n            }\n        }\n\n        /* couldn't find a trusted cert (& let self-signed errors \n           be returned) */\n        if (!match_ca_cert && !is_self_signed)\n        {\n            ret = X509_VFY_ERROR_NO_TRUSTED_CERT;       \n            goto end_verify;\n        }\n    }\n    else if (asn1_compare_dn(cert->ca_cert_dn, next_cert->cert_dn) != 0)\n    {\n        /* check the chain */\n        ret = X509_VFY_ERROR_INVALID_CHAIN;\n        goto end_verify;\n    }\n    else /* use the next certificate in the chain for signature verify */\n    {\n        ctx = next_cert->rsa_ctx->bi_ctx;\n        mod = next_cert->rsa_ctx->m;\n        expn = next_cert->rsa_ctx->e;\n    }\n\n    /* cert is self signed */\n    if (!match_ca_cert && is_self_signed)\n    {\n        ret = X509_VFY_ERROR_SELF_SIGNED;\n        goto end_verify;\n    }\n\n    /* check the signature */\n    cert_sig = sig_verify(ctx, cert->signature, cert->sig_len, \n                        bi_clone(ctx, mod), bi_clone(ctx, expn));\n\n    if (cert_sig && cert->digest)\n    {\n        if (bi_compare(cert_sig, cert->digest) != 0)\n            ret = X509_VFY_ERROR_BAD_SIGNATURE;\n\n\n        bi_free(ctx, cert_sig);\n    }\n    else\n    {\n        ret = X509_VFY_ERROR_BAD_SIGNATURE;\n    }\n\n    if (ret)\n        goto end_verify;\n\n    /* go down the certificate chain using recursion. */\n    if (next_cert != NULL)\n    {\n        ret = x509_verify(ca_cert_ctx, next_cert);\n    }\n\nend_verify:\n    return ret;\n}\n#endif\n\n#if defined (CONFIG_SSL_FULL_MODE)\n/**\n * Used for diagnostics.\n */\nstatic const char *not_part_of_cert = \"<Not Part Of Certificate>\";\nvoid ICACHE_FLASH_ATTR x509_print(const X509_CTX *cert, CA_CERT_CTX *ca_cert_ctx) \n{\n    if (cert == NULL)\n        return;\n\n    ssl_printf(\"=== CERTIFICATE ISSUED TO ===\\n\");\n    ssl_printf(\"Common Name (CN):\\t\\t\");\n    ssl_printf(\"%s\\n\", cert->cert_dn[X509_COMMON_NAME] ?\n                    cert->cert_dn[X509_COMMON_NAME] : not_part_of_cert);\n\n    ssl_printf(\"Organization (O):\\t\\t\");\n    ssl_printf(\"%s\\n\", cert->cert_dn[X509_ORGANIZATION] ?\n        cert->cert_dn[X509_ORGANIZATION] : not_part_of_cert);\n\n    ssl_printf(\"Organizational Unit (OU):\\t\");\n    ssl_printf(\"%s\\n\", cert->cert_dn[X509_ORGANIZATIONAL_UNIT] ?\n        cert->cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);\n\n    ssl_printf(\"=== CERTIFICATE ISSUED BY ===\\n\");\n    ssl_printf(\"Common Name (CN):\\t\\t\");\n    ssl_printf(\"%s\\n\", cert->ca_cert_dn[X509_COMMON_NAME] ?\n                    cert->ca_cert_dn[X509_COMMON_NAME] : not_part_of_cert);\n\n    ssl_printf(\"Organization (O):\\t\\t\");\n    ssl_printf(\"%s\\n\", cert->ca_cert_dn[X509_ORGANIZATION] ?\n        cert->ca_cert_dn[X509_ORGANIZATION] : not_part_of_cert);\n\n    ssl_printf(\"Organizational Unit (OU):\\t\");\n    ssl_printf(\"%s\\n\", cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] ?\n        cert->ca_cert_dn[X509_ORGANIZATIONAL_UNIT] : not_part_of_cert);\n\n    ssl_printf(\"Not Before:\\t\\t\\t%d\\n\", cert->not_before);   \n    ssl_printf(\"Not After:\\t\\t\\t%d\\n\", cert->not_after);    \n    ssl_printf(\"RSA bitsize:\\t\\t\\t%d\\n\", cert->rsa_ctx->num_octets*8);\n    ssl_printf(\"Sig Type:\\t\\t\\t\");\n    switch (cert->sig_type)\n    {\n        case SIG_TYPE_MD5:\n            ssl_printf(\"MD5\\n\");\n            break;\n        case SIG_TYPE_SHA1:\n            ssl_printf(\"SHA1\\n\");\n            break;\n        case SIG_TYPE_MD2:\n            ssl_printf(\"MD2\\n\");\n            break;\n        default:\n            ssl_printf(\"Unrecognized: %d\\n\", cert->sig_type);\n            break;\n    }\n\n    if (ca_cert_ctx)\n    {\n        ssl_printf(\"Verify:\\t\\t\\t\\t%s\\n\",\n                x509_display_error(x509_verify(ca_cert_ctx, cert)));\n    }\n\n#if 0\n    print_blob(\"Signature\", cert->signature, cert->sig_len);\n    bi_print(\"Modulus\", cert->rsa_ctx->m);\n    bi_print(\"Pub Exp\", cert->rsa_ctx->e);\n#endif\n\n    if (ca_cert_ctx)\n    {\n        x509_print(cert->next, ca_cert_ctx);\n    }\n\n    //TTY_FLUSH();\n}\n\nconst char * ICACHE_FLASH_ATTR x509_display_error(int error)\n{\n    switch (error)\n    {\n        case X509_OK:\n            return \"Certificate verify successful\";\n\n        case X509_NOT_OK:\n            return \"X509 not ok\";\n\n        case X509_VFY_ERROR_NO_TRUSTED_CERT:\n            return \"No trusted cert is available\";\n\n        case X509_VFY_ERROR_BAD_SIGNATURE:\n            return \"Bad signature\";\n\n        case X509_VFY_ERROR_NOT_YET_VALID:\n            return \"Cert is not yet valid\";\n\n        case X509_VFY_ERROR_EXPIRED:\n            return \"Cert has expired\";\n\n        case X509_VFY_ERROR_SELF_SIGNED:\n            return \"Cert is self-signed\";\n\n        case X509_VFY_ERROR_INVALID_CHAIN:\n            return \"Chain is invalid (check order of certs)\";\n\n        case X509_VFY_ERROR_UNSUPPORTED_DIGEST:\n            return \"Unsupported digest\";\n\n        case X509_INVALID_PRIV_KEY:\n            return \"Invalid private key\";\n\n        default:\n            return \"Unknown\";\n    }\n}\n#endif      /* CONFIG_SSL_FULL_MODE */\n\n"
  },
  {
    "path": "app/user/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = libuser.a\nendif\n\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../../include/ets\nINCLUDES += -I ../libc\nINCLUDES += -I ../platform\nINCLUDES += -I ../http\nINCLUDES += -I ../dns\nINCLUDES += -I ../\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/user/user_main.c",
    "content": "/******************************************************************************\n * Copyright 2013-2014 Espressif Systems (Wuxi)\n *\n * FileName: user_main.c\n *\n * Description: entry file of user application\n *\n * Modification history:\n *     2014/1/1, v1.0 create this file.\n*******************************************************************************/\n#include \"platform.h\"\n#include \"c_string.h\"\n#include \"c_stdlib.h\"\n#include \"c_stdio.h\"\n#include \"flash_api.h\"\n\n#include \"osapi.h\"\n\n#include \"user_interface.h\"\n#include \"user_config.h\"\n\n#include \"ets_sys.h\"\n#include \"driver/uart.h\"\n#include \"driver/relay.h\"\n#include \"mem.h\"\n\n#include \"dns.h\"\n#include \"serial_number.h\"\n\n#include \"http/app.h\"\n#include \"mqtt/app.h\"\n\n#include \"sensor/sensors.h\"\n\n#ifdef DEVELOP_VERSION\nos_timer_t heapTimer;\n\nstatic void heapTimerCb(void *arg){\n\n    NODE_DBG(\"FREE HEAP: %d\",system_get_free_heap_size());\n\n}\n\n#endif\n\n\n\n\nstatic void config_wifi(){\n    NODE_DBG(\"Putting AP UP\");\n\n    platform_key_led(0);    \n    \n    wifi_station_set_auto_connect(1); \n    wifi_set_opmode(0x03); // station+ap mode                       \n\n    struct softap_config config;\n    wifi_softap_get_config(&config);\n\n    char ssid[]=\"SmartRelay\"SERIAL_NUMBER;\n\n    strcpy(config.ssid,ssid);\n    memset(config.password,0,64);\n    config.ssid_len=strlen(ssid);\n    config.channel=11;\n    config.authmode=AUTH_OPEN;\n    config.max_connection=4;\n    config.ssid_hidden=0;\n\n    wifi_softap_set_config(&config);\n\n    \n}\n\n/******************************************************************************\n * FunctionName : user_init\n * Description  : entry of user application, init user function here\n * Parameters   : none\n * Returns      : none\n*******************************************************************************/\nvoid user_init(void)\n{   \n    \n    system_update_cpu_freq(160); //overclock :)\n\n    uart_init(BIT_RATE_115200,BIT_RATE_115200);\n\n    NODE_DBG(\"User Init\");\n\n    uint32_t size = flash_get_size_byte();\n    NODE_DBG(\"Flash size %d\",size);\n   \n    config_wifi();\n    \n\trelay_init();   \n    \n    init_dns();\n    init_http_server();\n\n    //uncomment to send data to mqtt broker\n    //mqtt_app_init();    \n\n    //uncomment if you have sensors intalled\n    //sensors_init();\n\n    #ifdef DEVELOP_VERSION\n\n    //arm timer\n    os_memset(&heapTimer,0,sizeof(os_timer_t));\n    os_timer_disarm(&heapTimer);\n    os_timer_setfn(&heapTimer, (os_timer_func_t *)heapTimerCb, NULL);\n    os_timer_arm(&heapTimer, 5000, 1);\n\n    #endif\n}\n"
  },
  {
    "path": "app/util/Makefile",
    "content": "\n#############################################################\n# Required variables for each makefile\n# Discard this section from all parent makefiles\n# Expected variables (with automatic defaults):\n#   CSRCS (all \"C\" files in the dir)\n#   SUBDIRS (all subdirs with a Makefile)\n#   GEN_LIBS - list of libs to be generated ()\n#   GEN_IMAGES - list of images to be generated ()\n#   COMPONENTS_xxx - a list of libs/objs in the form\n#     subdir/lib to be extracted and rolled up into\n#     a generated lib/image xxx.a ()\n#\nifndef PDIR\nGEN_LIBS = util.a\nendif\n\n#############################################################\n# Configuration i.e. compile options etc.\n# Target specific stuff (defines etc.) goes in here!\n# Generally values applying to a tree are captured in the\n#   makefile at its root level - these are then overridden\n#   for a subtree within the makefile rooted therein\n#\n#DEFINES += \n\n#############################################################\n# Recursion Magic - Don't touch this!!\n#\n# Each subtree potentially has an include directory\n#   corresponding to the common APIs applicable to modules\n#   rooted at that subtree. Accordingly, the INCLUDE PATH\n#   of a module can only contain the include directories up\n#   its parent path, and not its siblings\n#\n# Required for each makefile to inherit from the parent\n#\n\nINCLUDES := $(INCLUDES) -I $(PDIR)include\nINCLUDES += -I ./\nINCLUDES += -I ../libc\nPDIR := ../$(PDIR)\nsinclude $(PDIR)Makefile\n\n"
  },
  {
    "path": "app/util/base64.c",
    "content": "/*\n * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/* ====================================================================\n * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. All advertising materials mentioning features or use of this\n *    software must display the following acknowledgment:\n *    \"This product includes software developed by the Apache Group\n *    for use in the Apache HTTP server project (http://www.apache.org/).\"\n *\n * 4. The names \"Apache Server\" and \"Apache Group\" must not be used to\n *    endorse or promote products derived from this software without\n *    prior written permission. For written permission, please contact\n *    apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * 6. Redistributions of any form whatsoever must retain the following\n *    acknowledgment:\n *    \"This product includes software developed by the Apache Group\n *    for use in the Apache HTTP server project (http://www.apache.org/).\"\n *\n * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY\n * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Group and was originally based\n * on public domain software written at the National Center for\n * Supercomputing Applications, University of Illinois, Urbana-Champaign.\n * For more information on the Apache Group and the Apache HTTP server\n * project, please see <http://www.apache.org/>.\n *\n */\n\n/* Base64 encoder/decoder. Originally Apache file ap_base64.c\n */\n\n#include <string.h>\n\n#include \"base64.h\"\n\n/* aaaack but it's fast and const should make it shared text page. */\nstatic const unsigned char pr2six[256] =\n{\n    /* ASCII table */\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,\n    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,\n    64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,\n    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,\n    64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,\n    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64\n};\n\nint Base64decode_len(const char *bufcoded)\n{\n    int nbytesdecoded;\n    register const unsigned char *bufin;\n    register int nprbytes;\n\n    bufin = (const unsigned char *) bufcoded;\n    while (pr2six[*(bufin++)] <= 63);\n\n    nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;\n    nbytesdecoded = ((nprbytes + 3) / 4) * 3;\n\n    return nbytesdecoded + 1;\n}\n\nint Base64decode(char *bufplain, const char *bufcoded)\n{\n    int nbytesdecoded;\n    register const unsigned char *bufin;\n    register unsigned char *bufout;\n    register int nprbytes;\n\n    bufin = (const unsigned char *) bufcoded;\n    while (pr2six[*(bufin++)] <= 63);\n    nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;\n    nbytesdecoded = ((nprbytes + 3) / 4) * 3;\n\n    bufout = (unsigned char *) bufplain;\n    bufin = (const unsigned char *) bufcoded;\n\n    while (nprbytes > 4) {\n    *(bufout++) =\n        (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);\n    *(bufout++) =\n        (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);\n    *(bufout++) =\n        (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);\n    bufin += 4;\n    nprbytes -= 4;\n    }\n\n    /* Note: (nprbytes == 1) would be an error, so just ingore that case */\n    if (nprbytes > 1) {\n    *(bufout++) =\n        (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);\n    }\n    if (nprbytes > 2) {\n    *(bufout++) =\n        (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);\n    }\n    if (nprbytes > 3) {\n    *(bufout++) =\n        (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);\n    }\n\n    *(bufout++) = '\\0';\n    nbytesdecoded -= (4 - nprbytes) & 3;\n    return nbytesdecoded;\n}\n\nstatic const char basis_64[] =\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\nint Base64encode_len(int len)\n{\n    return ((len + 2) / 3 * 4) + 1;\n}\n\nint Base64encode(char *encoded, const char *string, int len)\n{\n    int i;\n    char *p;\n\n    p = encoded;\n    for (i = 0; i < len - 2; i += 3) {\n    *p++ = basis_64[(string[i] >> 2) & 0x3F];\n    *p++ = basis_64[((string[i] & 0x3) << 4) |\n                    ((int) (string[i + 1] & 0xF0) >> 4)];\n    *p++ = basis_64[((string[i + 1] & 0xF) << 2) |\n                    ((int) (string[i + 2] & 0xC0) >> 6)];\n    *p++ = basis_64[string[i + 2] & 0x3F];\n    }\n    if (i < len) {\n    *p++ = basis_64[(string[i] >> 2) & 0x3F];\n    if (i == (len - 1)) {\n        *p++ = basis_64[((string[i] & 0x3) << 4)];\n        *p++ = '=';\n    }\n    else {\n        *p++ = basis_64[((string[i] & 0x3) << 4) |\n                        ((int) (string[i + 1] & 0xF0) >> 4)];\n        *p++ = basis_64[((string[i + 1] & 0xF) << 2)];\n    }\n    *p++ = '=';\n    }\n\n    *p++ = '\\0';\n    return p - encoded;\n}"
  },
  {
    "path": "app/util/base64.h",
    "content": "/*\n * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.\n *\n * @APPLE_LICENSE_HEADER_START@\n * \n * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.\n * \n * This file contains Original Code and/or Modifications of Original Code\n * as defined in and that are subject to the Apple Public Source License\n * Version 2.0 (the 'License'). You may not use this file except in\n * compliance with the License. Please obtain a copy of the License at\n * http://www.opensource.apple.com/apsl/ and read it before using this\n * file.\n * \n * The Original Code and all software distributed under the License are\n * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\n * Please see the License for the specific language governing rights and\n * limitations under the License.\n * \n * @APPLE_LICENSE_HEADER_END@\n */\n/* ====================================================================\n * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. All advertising materials mentioning features or use of this\n *    software must display the following acknowledgment:\n *    \"This product includes software developed by the Apache Group\n *    for use in the Apache HTTP server project (http://www.apache.org/).\"\n *\n * 4. The names \"Apache Server\" and \"Apache Group\" must not be used to\n *    endorse or promote products derived from this software without\n *    prior written permission. For written permission, please contact\n *    apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * 6. Redistributions of any form whatsoever must retain the following\n *    acknowledgment:\n *    \"This product includes software developed by the Apache Group\n *    for use in the Apache HTTP server project (http://www.apache.org/).\"\n *\n * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY\n * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Group and was originally based\n * on public domain software written at the National Center for\n * Supercomputing Applications, University of Illinois, Urbana-Champaign.\n * For more information on the Apache Group and the Apache HTTP server\n * project, please see <http://www.apache.org/>.\n *\n */\n\n\n\n#ifndef _BASE64_H_\n#define _BASE64_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint Base64encode_len(int len);\nint Base64encode(char * coded_dst, const char *plain_src,int len_plain_src);\n\nint Base64decode_len(const char * coded_src);\nint Base64decode(char * plain_dst, const char *coded_src);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif //_BASE64_H_"
  },
  {
    "path": "app/util/linked_list.c",
    "content": "#include \"mem.h\"\n#include \"linked_list.h\"\n#include \"osapi.h\"\n\n/** create anode\n */\nstatic node* list_create_node (void* item) {\n    node* n = (node*) os_malloc (sizeof(node));\n    n->item = item;\n    n->prev = NULL;\n    n->next = NULL;\n    return n;\n}\n\n/** add item to head\n */\nvoid list_add_first (linked_list* _this,void* item) {\n    node* newNode = list_create_node(item);\n    node* head = _this->head;\n    // list is empty\n    if (head == NULL)\n        _this->head = newNode;\n    else { // has item(s)\n        node* last = _this->tail;\n        if (last == NULL) // only head node\n            last = head;\n        newNode->next = head;\n        head->prev = newNode;\n        _this->head = newNode;\n        _this->tail = last;\n    }\n\n    _this->size++;\n}\n\n/** add item to tail\n */\nvoid list_add_last (linked_list* _this, void* item) {\n   node* newNode = list_create_node(item);\n   node* head = _this->head;\n   node* tail = _this->tail;\n    // list is empty\n    if (head == NULL)\n        _this->head = newNode;\n    else { // has item(s)\n       node* lastNode = tail;\n        if (tail == NULL) // only head node\n            lastNode = head;\n        lastNode->next = newNode;\n        newNode->prev = lastNode;\n        _this->tail = newNode;\n    }\n    _this->size++;\n}\n\n/** add item to any position\n */\nvoid list_add (linked_list* _this, void* item, int position) {\n     // index out of list size\n     if (position > _this->size) {\n       return;\n    }\n    // add to head\n    if (position == 0) {\n        list_add_first(_this, item);\n    } else if (position == _this->size) {\n        // add to tail\n        list_add_last(_this, item);\n    } else {\n        // insert between head and tail\n\n       node* n = _this->head;\n        int i = 0;\n        // loop until the position\n        while (i < position) {\n            n = n->next;\n            i++;\n        }\n        // insert new node to position\n        node* newNode = list_create_node(item);\n        list_insert_before(_this, n, newNode);\n        _this->size++;\n    }\n}\n\n\n/** insert one node before another,\n * newNdoe, node and node->prev should not be null.\n */\nvoid list_insert_before (linked_list* _this,node* n,node* newNode) {\n    node* prev = n->prev;\n\n    n->prev = newNode;\n    newNode->next = n;\n    prev->next = newNode;\n    newNode->prev = prev;\n}\n\n/** get item from specific position\n */\nvoid* list_get (linked_list* _this, int position) {\n    // list is empty\n    if (_this->size == 0) {\n        //NODE_DBG(\"LinkedList#get: The list is empty.\");\n       return NULL;\n    } else if (position >= _this->size) {\n        // out of bound\n        //NODE_DBG(\"LinkedList#get: Index out of bound\");\n        return NULL;\n    }\n    // get head item\n    if (position == 0) {\n        return list_get_first(_this);\n    } else if (position+1 == _this->size) {\n        // get tail item\n        return list_get_last(_this);\n    } else {\n       node* node = _this->head;\n        int i = 0;\n        // loop until position\n        while (i < position) {\n            node = node->next;\n            i++;\n        }\n        return node->item;\n    }\n}\n/** get item from head\n */\nvoid* list_get_first (linked_list* _this) {\n    // list is empty\n    if (_this->size == 0) {\n        //NODE_DBG(\"LinkedList#getFirst: The list is empty.\");\n        return NULL;\n    }\n    return _this->head->item;\n}\n\n/** get item from tail\n */\nvoid* list_get_last (linked_list* _this) {\n    // list is empty\n    if (_this->size == 0) {\n        //NODE_DBG(\"LinkedList#getLast: The list is empty.\");\n        return NULL;\n    }\n    // only head node\n    if (_this->size == 1) {\n        return list_get_first(_this);\n    }\n    return _this->tail->item;\n}\n\n\nvoid* list_remove_node(linked_list* _this,node *n){\n\n     // list is empty\n    if (_this->size == 0) {\n        //NODE_DBG(\"LinkedList#_remove: The list is empty.\");\n        return NULL;\n    }\n\n    if(n->prev!=NULL)\n        n->prev->next = n->next;\n    else\n        _this->head=n->next;\n    if(n->next!=NULL)\n        n->next->prev = n->prev;\n    else\n        _this->tail = n->prev;\n\n    void* r = n->item;\n\n    os_free(n);\n\n    return r;\n}\n\n/** get item and remove it from any position\n */\nvoid* list_remove (linked_list* _this, int position) {\n    // list is empty\n    if (_this->size == 0) {\n        //NODE_DBG(\"LinkedList#_remove: The list is empty.\");\n        return NULL;\n    } else if (position >= _this->size) {\n        // out of bound\n        //NODE_DBG(\"LinkedList#_remove: Index out of bound\");\n        return NULL;\n    }\n\n    // remove from head\n    if (position == 0) {\n        return list_remove_first(_this);\n    } else if (position+1 == _this->size) {\n        // remove from tail\n        return list_remove_last(_this);\n    } else {\n       node* n = _this->head;\n       node* prev;\n       node* next;\n        int i = 0;\n        void* item;\n        // loop until position\n        while (i < position) {\n            n = n->next;\n            i++;\n        }\n        item = n->item;\n        // remove node from list\n        prev = n->prev;\n        next = n->next;\n        prev->next = next;\n        next->prev = prev;\n        os_free(n);\n        _this->size--;\n        return item ;\n    }\n}\n/** get and remove item from head\n */\nvoid* list_remove_first (linked_list* _this) {\n   node* head = _this->head;\n   node* next;\n    void* item;\n    // list is empty\n    if (head == NULL) {\n        //NODE_DBG(\"LinkedList#_removeFirst: The list is empty.\");\n        return NULL;\n    }\n    item = head->item;\n    next = head->next;\n    _this->head = next;\n    if (next != NULL) // has next item\n        next->prev = NULL;\n    os_free(head);\n    _this->size--;\n    if (_this->size <= 1) // empty or only head node\n        _this->tail = NULL;\n    return item;\n}\n\n/** get and remove item from tail\n */\nvoid* list_remove_last (linked_list* _this) {\n    // list is empty\n    if (_this->size == 0) {\n        //NODE_DBG(\"LinkedList#_removeLast: The list is empty.\");\n        return NULL;\n    }\n    if (_this->size == 1) { // only head node\n        return list_remove_first(_this);\n    } else {\n       node* tail = _this->tail;\n       node* prev = tail->prev;\n        void* item = tail->item;\n        prev->next = NULL;\n        os_free(tail);\n        if (_this->size > 1)\n            _this->tail = prev;\n        _this->size--;\n        if (_this->size <= 1) // empty or only head node\n            _this->tail = NULL;\n        return item;\n    }\n}\n\n/** create a LinkedList\n */\nlinked_list* create_linked_list () {\n\n    linked_list *list = (linked_list *)os_malloc(sizeof(linked_list));\n    init_linked_list(list);\n    return list;\n}\n\nvoid init_linked_list(linked_list *list){\n    \n    os_memset(list,0,sizeof(linked_list));\n    list->head = NULL;\n    list->tail = NULL;\n    \n    list->size=0;\n}\n"
  },
  {
    "path": "app/util/linked_list.h",
    "content": "/* \n * File:   LinkedList.h\n * Author: me_000\n *\n * Created on 6 de Julho de 2015, 15:21\n */\n\n#ifndef LINKEDLIST_H\n#define\tLINKEDLIST_H\n\n#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n    \n/**\n * The Node struct,\n * contains item and the pointers that point to previous node/next node.\n */\ntypedef struct node {\n    void* item;\n    // previous node\n    struct node* prev;\n    // next node\n    struct node* next;\n} node;\n\n\n\n/**\n * The LinkedList struct, contains the pointers that\n * point to first node and last node, the size of the LinkedList,\n * and the function pointers.\n */\ntypedef struct linked_list {\n    node* head;\n    node* tail;\n    // size of this LinkedList\n    int size;\n} linked_list;\n\nvoid list_add_first (linked_list* _this, void* item);\nvoid list_add_last (linked_list* _this, void* item);\nvoid list_add (linked_list* _this, void* item, int position);\nvoid list_insert_before (linked_list* _this, node* previous_node, node* new_node);\nvoid* list_get (linked_list* _this, int position);\nvoid* list_get_first (linked_list* _this);\nvoid* list_get_last (linked_list* _this);\nvoid* list_remove_node(linked_list* _this, node *node_to_remove);\nvoid* list_remove (linked_list* _this, int position);\nvoid* list_remove_first (linked_list* _this);\nvoid* list_remove_last (linked_list* _this);\nlinked_list* create_linked_list ();\nvoid init_linked_list(linked_list *list);\n\n\n#ifdef\t__cplusplus\n}\n#endif\n\n#endif\t/* LINKEDLIST_H */\n\n"
  },
  {
    "path": "bin/.gitignore",
    "content": "*\n*.S\n*.dump\n*.bin\n*.bin_rep\n!.gitignore\n!blank.bin\n!esp_init_data_default.bin\n"
  },
  {
    "path": "include/at_custom.h",
    "content": "\n/*\n * custom_at.h\n *\n * This file is part of Espressif's AT+ command set program.\n * Copyright (C) 2013 - 2016, Espressif Systems\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of version 3 of the GNU General Public License as\n * published by the Free Software Foundation.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License along\n * with this program.  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef CUSTOM_AT_H_\n#define CUSTOM_AT_H_\n\n#include \"c_types.h\"\n\ntypedef struct\n{\n  char *at_cmdName;\n  int8_t at_cmdLen;\n  void (*at_testCmd)(uint8_t id);\n  void (*at_queryCmd)(uint8_t id);\n  void (*at_setupCmd)(uint8_t id, char *pPara);\n  void (*at_exeCmd)(uint8_t id);\n}at_funcationType;\n\nextern uint8 at_customLinkMax;\n/**\n  * @brief  Response \"OK\" to uart.\n  * @param  None\n  * @retval None\n  */\nvoid at_response_ok(void);\n/**\n  * @brief  Response \"ERROR\" to uart.\n  * @param  events: no used\n  * @retval None\n  */\nvoid at_response_error(void);\n/**\n  * @brief  Task of process command or txdata.\n  * @param  custom_at_cmd_array: the array of at cmd that custom defined\n  *         cmd_num : the num of at cmd that custom defined\n  * @retval None\n  */\nvoid at_cmd_array_regist(at_funcationType *custom_at_cmd_array,uint32 cmd_num);\n/**\n  * @brief  get digit form at cmd line.the maybe alter pSrc\n  * @param  p_src: at cmd line string\n  *         result:the buffer to be placed result\n  *         err : err num\n  * @retval TRUE:\n  *         FALSE:\n  */\nbool at_get_next_int_dec(char **p_src,int*result,int* err);\n/**\n  * @brief  get string form at cmd line.the maybe alter pSrc\n  * @param  p_dest: the buffer to be placed result\n  *         p_src: at cmd line string\n  *         max_len :max len of string excepted to get\n  * @retval None\n  */\nint32 at_data_str_copy(char *p_dest, char **p_src, int32 max_len);\n\n/**\n  * @brief  initialize at module\n  * @param  None\n  * @retval None\n  */\nvoid at_init(void);\n/**\n  * @brief  print string to at port\n  * @param  string\n  * @retval None\n  */\nvoid at_port_print(const char *str);\n/**\n  * @brief  print custom information when AT+GMR\n  * @param  string\n  * @retval None\n  */\nvoid at_set_custom_info(char* info);\n/**\n  * @brief  if current at command is processing,you can call at_enter_special_state,\n  *         then if other comamnd coming,it will return busy.\n  * @param  None\n  * @retval None\n  */\nvoid at_enter_special_state(void);\n/**\n  * @brief  \n  * @param  None\n  * @retval None\n  */\nvoid at_leave_special_state(void);\n/**\n  * @brief  get at version\n  * @param  None\n  * @retval at version\n  *         bit24~31: at main version\n  *         bit23~16: at sub version\n  *         bit15~8 : at test version\n  *         bit7~0  : customized version\n  */\nuint32 at_get_version(void);\n#endif\n"
  },
  {
    "path": "include/c_types.h",
    "content": "/*\n *  Copyright (c) 2010 - 2011 Espressif System\n *\n */\n\n#ifndef _C_TYPES_H_\n#define _C_TYPES_H_\n\ntypedef unsigned char       uint8_t;\ntypedef signed char         sint8_t;\ntypedef signed char         int8_t;\ntypedef unsigned short      uint16_t;\ntypedef signed short        sint16_t;\ntypedef signed short        int16_t;\ntypedef unsigned long       uint32_t;\ntypedef signed long         sint32_t;\ntypedef signed long         int32_t;\ntypedef signed long long    sint64_t;\ntypedef unsigned long long  uint64_t;\ntypedef unsigned long long  u_int64_t;\ntypedef float               real32_t;\ntypedef double              real64_t;\n\ntypedef unsigned char       uint8;\ntypedef unsigned char       u8;\ntypedef signed char         sint8;\ntypedef signed char         int8;\ntypedef signed char         s8;\ntypedef unsigned short      uint16;\ntypedef unsigned short      u16;\ntypedef signed short        sint16;\ntypedef signed short        s16;\ntypedef unsigned int        uint32;\ntypedef unsigned int        u_int;\ntypedef unsigned int        u32;\ntypedef signed int          sint32;\ntypedef signed int          s32;\ntypedef int                 int32;\ntypedef signed long long    sint64;\ntypedef unsigned long long  uint64;\ntypedef unsigned long long  u64;\ntypedef float               real32;\ntypedef double              real64;\n\n#define __le16      u16\n\ntypedef unsigned int        size_t;\n\n#define __packed        __attribute__((packed))\n\n#define LOCAL       static\n\n#ifndef NULL\n#define NULL (void *)0\n#endif /* NULL */\n\n/* probably should not put STATUS here */\ntypedef enum {\n    OK = 0,\n    FAIL,\n    PENDING,\n    BUSY,\n    CANCEL,\n} STATUS;\n\n#define BIT(nr)                 (1UL << (nr))\n\n#define REG_SET_BIT(_r, _b)  (*(volatile uint32_t*)(_r) |= (_b))\n#define REG_CLR_BIT(_r, _b)  (*(volatile uint32_t*)(_r) &= ~(_b))\n\n#define DMEM_ATTR __attribute__((section(\".bss\")))\n#define SHMEM_ATTR\n\n#ifdef ICACHE_FLASH\n#define ICACHE_FLASH_ATTR __attribute__((section(\".irom0.text\")))\n#define ICACHE_RODATA_ATTR __attribute__((section(\".irom.text\")))\n#else\n#define ICACHE_FLASH_ATTR\n#define ICACHE_RODATA_ATTR\n#endif /* ICACHE_FLASH */\n\n#define STORE_ATTR __attribute__((aligned(4)))\n\n#ifndef __cplusplus\ntypedef unsigned char   bool;\n#define BOOL            bool\n#define true            (1)\n#define false           (0)\n#define TRUE            true\n#define FALSE           false\n\n\n#endif /* !__cplusplus */\n\n#endif /* _C_TYPES_H_ */\n"
  },
  {
    "path": "include/eagle_soc.h",
    "content": "/*\n *  Copyright (c) Espressif System 2010 - 2012\n *\n */\n\n#ifndef _EAGLE_SOC_H_\n#define _EAGLE_SOC_H_\n\n//Register Bits{{\n#define BIT31   0x80000000\n#define BIT30   0x40000000\n#define BIT29   0x20000000\n#define BIT28   0x10000000\n#define BIT27   0x08000000\n#define BIT26   0x04000000\n#define BIT25   0x02000000\n#define BIT24   0x01000000\n#define BIT23   0x00800000\n#define BIT22   0x00400000\n#define BIT21   0x00200000\n#define BIT20   0x00100000\n#define BIT19   0x00080000\n#define BIT18   0x00040000\n#define BIT17   0x00020000\n#define BIT16   0x00010000\n#define BIT15   0x00008000\n#define BIT14   0x00004000\n#define BIT13   0x00002000\n#define BIT12   0x00001000\n#define BIT11   0x00000800\n#define BIT10   0x00000400\n#define BIT9     0x00000200\n#define BIT8     0x00000100\n#define BIT7     0x00000080\n#define BIT6     0x00000040\n#define BIT5     0x00000020\n#define BIT4     0x00000010\n#define BIT3     0x00000008\n#define BIT2     0x00000004\n#define BIT1     0x00000002\n#define BIT0     0x00000001\n//}}\n\n//Registers Operation {{\n#define ETS_UNCACHED_ADDR(addr) (addr)\n#define ETS_CACHED_ADDR(addr) (addr)\n\n\n#define READ_PERI_REG(addr) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr)))\n#define WRITE_PERI_REG(addr, val) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val)\n#define CLEAR_PERI_REG_MASK(reg, mask) WRITE_PERI_REG((reg), (READ_PERI_REG(reg)&(~(mask))))\n#define SET_PERI_REG_MASK(reg, mask)   WRITE_PERI_REG((reg), (READ_PERI_REG(reg)|(mask)))\n#define GET_PERI_REG_BITS(reg, hipos,lowpos)      ((READ_PERI_REG(reg)>>(lowpos))&((1<<((hipos)-(lowpos)+1))-1))\n#define SET_PERI_REG_BITS(reg,bit_map,value,shift) (WRITE_PERI_REG((reg),(READ_PERI_REG(reg)&(~((bit_map)<<(shift))))|((value)<<(shift)) ))\n//}}\n\n//Periheral Clock {{\n#define  CPU_CLK_FREQ                                80*1000000       //unit: Hz\n#define  APB_CLK_FREQ                                CPU_CLK_FREQ\n#define  UART_CLK_FREQ                               APB_CLK_FREQ\n#define  TIMER_CLK_FREQ                              (APB_CLK_FREQ>>8) //divided by 256\n//}}\n\n//Peripheral device base address define{{\n#define PERIPHS_DPORT_BASEADDR              0x3ff00000\n#define PERIPHS_GPIO_BASEADDR               0x60000300\n#define PERIPHS_TIMER_BASEDDR               0x60000600\n#define PERIPHS_RTC_BASEADDR                0x60000700\n#define PERIPHS_IO_MUX\t\t\t\t\t\t0x60000800\n//}}\n\n//Interrupt remap control registers define{{\n#define EDGE_INT_ENABLE_REG                 (PERIPHS_DPORT_BASEADDR+0x04)\n#define TM1_EDGE_INT_ENABLE()             SET_PERI_REG_MASK(EDGE_INT_ENABLE_REG, BIT1)\n#define TM1_EDGE_INT_DISABLE()            CLEAR_PERI_REG_MASK(EDGE_INT_ENABLE_REG, BIT1)\n//}}\n\n//GPIO reg {{\n#define GPIO_REG_READ(reg)                         READ_PERI_REG(PERIPHS_GPIO_BASEADDR + reg)\n#define GPIO_REG_WRITE(reg, val)                 WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + reg, val)\n#define GPIO_OUT_ADDRESS                         0x00\n#define GPIO_OUT_W1TS_ADDRESS             0x04\n#define GPIO_OUT_W1TC_ADDRESS             0x08\n\n#define GPIO_ENABLE_ADDRESS                  0x0c\n#define GPIO_ENABLE_W1TS_ADDRESS      0x10\n#define GPIO_ENABLE_W1TC_ADDRESS      0x14\n#define GPIO_OUT_W1TC_DATA_MASK      0x0000ffff\n\n#define GPIO_IN_ADDRESS                            0x18\n\n#define GPIO_STATUS_ADDRESS                  0x1c\n#define GPIO_STATUS_W1TS_ADDRESS       0x20\n#define GPIO_STATUS_W1TC_ADDRESS      0x24\n#define GPIO_STATUS_INTERRUPT_MASK 0x0000ffff\n\n#define GPIO_RTC_CALIB_SYNC                  PERIPHS_GPIO_BASEADDR+0x6c\n#define RTC_CALIB_START                           BIT31  //first write to zero, then to one to start\n#define RTC_PERIOD_NUM_MASK              0x3ff   //max 8ms\n#define GPIO_RTC_CALIB_VALUE               PERIPHS_GPIO_BASEADDR+0x70\n#define RTC_CALIB_RDY_S                           31  //after measure, flag to one, when start from zero to one, turn to zero\n#define RTC_CALIB_VALUE_MASK             0xfffff\n\n#define GPIO_PIN0_ADDRESS                        0x28\n\n#define GPIO_ID_PIN0                                     0\n#define GPIO_ID_PIN(n)                                   (GPIO_ID_PIN0+(n))\n#define GPIO_LAST_REGISTER_ID                GPIO_ID_PIN(15)\n#define GPIO_ID_NONE                                  0xffffffff\n\n#define GPIO_PIN_COUNT                              16\n\n#define GPIO_PIN_CONFIG_MSB                    12\n#define GPIO_PIN_CONFIG_LSB                     11\n#define GPIO_PIN_CONFIG_MASK                 0x00001800\n#define GPIO_PIN_CONFIG_GET(x)                 (((x) & GPIO_PIN_CONFIG_MASK) >> GPIO_PIN_CONFIG_LSB)\n#define GPIO_PIN_CONFIG_SET(x)                  (((x) << GPIO_PIN_CONFIG_LSB) & GPIO_PIN_CONFIG_MASK)\n\n#define GPIO_WAKEUP_ENABLE                               1\n#define GPIO_WAKEUP_DISABLE                              (~GPIO_WAKEUP_ENABLE)\n#define GPIO_PIN_WAKEUP_ENABLE_MSB             10\n#define GPIO_PIN_WAKEUP_ENABLE_LSB              10\n#define GPIO_PIN_WAKEUP_ENABLE_MASK          0x00000400\n#define GPIO_PIN_WAKEUP_ENABLE_GET(x)          (((x) & GPIO_PIN_WAKEUP_ENABLE_MASK) >> GPIO_PIN_WAKEUP_ENABLE_LSB)\n#define GPIO_PIN_WAKEUP_ENABLE_SET(x)           (((x) << GPIO_PIN_WAKEUP_ENABLE_LSB) & GPIO_PIN_WAKEUP_ENABLE_MASK)\n\n#define GPIO_PIN_INT_TYPE_MASK             0x380\n#define GPIO_PIN_INT_TYPE_MSB                9\n#define GPIO_PIN_INT_TYPE_LSB                 7\n#define GPIO_PIN_INT_TYPE_GET(x)             (((x) & GPIO_PIN_INT_TYPE_MASK) >> GPIO_PIN_INT_TYPE_LSB)\n#define GPIO_PIN_INT_TYPE_SET(x)             (((x) << GPIO_PIN_INT_TYPE_LSB) & GPIO_PIN_INT_TYPE_MASK)\n\n#define GPIO_PAD_DRIVER_ENABLE             1\n#define GPIO_PAD_DRIVER_DISABLE            (~GPIO_PAD_DRIVER_ENABLE)\n#define GPIO_PIN_PAD_DRIVER_MSB            2\n#define GPIO_PIN_PAD_DRIVER_LSB             2\n#define GPIO_PIN_PAD_DRIVER_MASK         0x00000004\n#define GPIO_PIN_PAD_DRIVER_GET(x)         (((x) & GPIO_PIN_PAD_DRIVER_MASK) >> GPIO_PIN_PAD_DRIVER_LSB)\n#define GPIO_PIN_PAD_DRIVER_SET(x)          (((x) << GPIO_PIN_PAD_DRIVER_LSB) & GPIO_PIN_PAD_DRIVER_MASK)\n\n#define GPIO_AS_PIN_SOURCE                        0\n#define SIGMA_AS_PIN_SOURCE                     (~GPIO_AS_PIN_SOURCE)\n#define GPIO_PIN_SOURCE_MSB                     0\n#define GPIO_PIN_SOURCE_LSB                      0\n#define GPIO_PIN_SOURCE_MASK                  0x00000001\n#define GPIO_PIN_SOURCE_GET(x)                 (((x) & GPIO_PIN_SOURCE_MASK) >> GPIO_PIN_SOURCE_LSB)\n#define GPIO_PIN_SOURCE_SET(x)                  (((x) << GPIO_PIN_SOURCE_LSB) & GPIO_PIN_SOURCE_MASK)\n// }}\n\n// TIMER reg {{\n#define RTC_REG_READ(addr)                        READ_PERI_REG(PERIPHS_TIMER_BASEDDR + addr)\n#define RTC_REG_WRITE(addr, val)                WRITE_PERI_REG(PERIPHS_TIMER_BASEDDR + addr, val)\n#define RTC_CLR_REG_MASK(reg, mask)      CLEAR_PERI_REG_MASK(PERIPHS_TIMER_BASEDDR +reg, mask)\n/* Returns the current time according to the timer timer. */\n#define NOW()                                                 RTC_REG_READ(FRC2_COUNT_ADDRESS)\n\n//load initial_value to timer1\n#define FRC1_LOAD_ADDRESS                    0x00\n\n//timer1's counter value(count from initial_value to 0)\n#define FRC1_COUNT_ADDRESS                 0x04\n\n#define FRC1_CTRL_ADDRESS                    0x08\n\n//clear timer1's interrupt when write this address\n#define FRC1_INT_ADDRESS                      0x0c\n#define FRC1_INT_CLR_MASK                   0x00000001\n\n//timer2's counter value(count from initial_value to 0)\n#define FRC2_COUNT_ADDRESS                0x24\n// }}\n\n//RTC reg {{\n#define REG_RTC_BASE  PERIPHS_RTC_BASEADDR\n\n#define RTC_GPIO_OUT                            (REG_RTC_BASE + 0x068)\n#define RTC_GPIO_ENABLE                         (REG_RTC_BASE + 0x074)\n#define RTC_GPIO_IN_DATA                        (REG_RTC_BASE + 0x08C)\n#define RTC_GPIO_CONF                           (REG_RTC_BASE + 0x090)\n#define PAD_XPD_DCDC_CONF                       (REG_RTC_BASE + 0x0A0)\n//}}\n\n//PIN Mux reg {{\n#define PERIPHS_IO_MUX_FUNC             0x13\n#define PERIPHS_IO_MUX_FUNC_S           4\n#define PERIPHS_IO_MUX_PULLUP           BIT7\n#define PERIPHS_IO_MUX_PULLDWN          BIT6\n#define PERIPHS_IO_MUX_SLEEP_PULLUP     BIT3\n#define PERIPHS_IO_MUX_SLEEP_PULLDWN    BIT2\n#define PERIPHS_IO_MUX_SLEEP_OE         BIT1\n#define PERIPHS_IO_MUX_OE               BIT0\n\n#define PERIPHS_IO_MUX_CONF_U           (PERIPHS_IO_MUX + 0x00)\n#define SPI0_CLK_EQU_SYS_CLK            BIT8\n#define SPI1_CLK_EQU_SYS_CLK            BIT9\n#define PERIPHS_IO_MUX_MTDI_U           (PERIPHS_IO_MUX + 0x04)\n#define FUNC_GPIO12                     3\n#define PERIPHS_IO_MUX_MTCK_U           (PERIPHS_IO_MUX + 0x08)\n#define FUNC_GPIO13                     3\n#define PERIPHS_IO_MUX_MTMS_U           (PERIPHS_IO_MUX + 0x0C)\n#define FUNC_GPIO14                     3\n#define PERIPHS_IO_MUX_MTDO_U           (PERIPHS_IO_MUX + 0x10)\n#define FUNC_GPIO15                     3\n#define FUNC_U0RTS                      4\n#define PERIPHS_IO_MUX_U0RXD_U          (PERIPHS_IO_MUX + 0x14)\n#define FUNC_U0RXD                      0\n#define FUNC_GPIO3                      3\n#define PERIPHS_IO_MUX_U0TXD_U          (PERIPHS_IO_MUX + 0x18)\n#define FUNC_U0TXD                      0\n#define FUNC_GPIO1                      3\n#define PERIPHS_IO_MUX_SD_CLK_U         (PERIPHS_IO_MUX + 0x1c)\n#define FUNC_SDCLK                      0\n#define FUNC_SPICLK                     1\n#define PERIPHS_IO_MUX_SD_DATA0_U       (PERIPHS_IO_MUX + 0x20)\n#define FUNC_SDDATA0                    0\n#define FUNC_SPIQ                       1\n#define FUNC_U1TXD                      4\n#define PERIPHS_IO_MUX_SD_DATA1_U       (PERIPHS_IO_MUX + 0x24)\n#define FUNC_SDDATA1                    0\n#define FUNC_SPID                       1\n#define FUNC_U1RXD                      4\n#define FUNC_SDDATA1_U1RXD              7\n#define PERIPHS_IO_MUX_SD_DATA2_U       (PERIPHS_IO_MUX + 0x28)\n#define FUNC_SDDATA2                    0\n#define FUNC_SPIHD                      1\n#define FUNC_GPIO9                      3\n#define PERIPHS_IO_MUX_SD_DATA3_U       (PERIPHS_IO_MUX + 0x2c)\n#define FUNC_SDDATA3                    0\n#define FUNC_SPIWP                      1\n#define FUNC_GPIO10                     3\n#define PERIPHS_IO_MUX_SD_CMD_U         (PERIPHS_IO_MUX + 0x30)\n#define FUNC_SDCMD                      0\n#define FUNC_SPICS0                     1\n#define PERIPHS_IO_MUX_GPIO0_U          (PERIPHS_IO_MUX + 0x34)\n#define FUNC_GPIO0                      0\n#define PERIPHS_IO_MUX_GPIO2_U          (PERIPHS_IO_MUX + 0x38)\n#define FUNC_GPIO2                      0\n#define FUNC_U1TXD_BK                   2\n#define FUNC_U0TXD_BK                   4\n#define PERIPHS_IO_MUX_GPIO4_U          (PERIPHS_IO_MUX + 0x3C)\n#define FUNC_GPIO4                      0\n#define PERIPHS_IO_MUX_GPIO5_U          (PERIPHS_IO_MUX + 0x40)\n#define FUNC_GPIO5                      0\n\n#define PIN_PULLUP_DIS(PIN_NAME)                 CLEAR_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP)\n#define PIN_PULLUP_EN(PIN_NAME)                  SET_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLUP)\n#define PIN_PULLDWN_DIS(PIN_NAME)             CLEAR_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLDWN)\n#define PIN_PULLDWN_EN(PIN_NAME)              SET_PERI_REG_MASK(PIN_NAME, PERIPHS_IO_MUX_PULLDWN)\n#define PIN_FUNC_SELECT(PIN_NAME, FUNC)  do { \\\n        CLEAR_PERI_REG_MASK(PIN_NAME, (PERIPHS_IO_MUX_FUNC<<PERIPHS_IO_MUX_FUNC_S)); \\\n        SET_PERI_REG_MASK(PIN_NAME, (((FUNC&BIT2)<<2)|(FUNC&0x3))<<PERIPHS_IO_MUX_FUNC_S); \\\n    } while (0)\n\n//}}\n\n#endif //_EAGLE_SOC_H_\n"
  },
  {
    "path": "include/espconn.h",
    "content": "#ifndef __ESPCONN_H__\r\n#define __ESPCONN_H__\r\n\r\ntypedef sint8 err_t;\r\n\r\ntypedef void *espconn_handle;\r\ntypedef void (* espconn_connect_callback)(void *arg);\r\ntypedef void (* espconn_reconnect_callback)(void *arg, sint8 err);\r\n\r\n/* Definitions for error constants. */\r\n\r\n#define ESPCONN_OK          0    /* No error, everything OK. */\r\n#define ESPCONN_MEM        -1    /* Out of memory error.     */\r\n#define ESPCONN_TIMEOUT    -3    /* Timeout.                 */\r\n#define ESPCONN_RTE        -4    /* Routing problem.         */\r\n#define ESPCONN_INPROGRESS  -5    /* Operation in progress    */\r\n#define ESPCONN_MAXNUM      -7   /* Total number exceeds the set maximum*/\r\n\r\n#define ESPCONN_ABRT       -8    /* Connection aborted.      */\r\n#define ESPCONN_RST        -9    /* Connection reset.        */\r\n#define ESPCONN_CLSD       -10   /* Connection closed.       */\r\n#define ESPCONN_CONN       -11   /* Not connected.           */\r\n\r\n#define ESPCONN_ARG        -12   /* Illegal argument.        */\r\n#define ESPCONN_IF         -14   /* UDP send error           */\r\n#define ESPCONN_ISCONN     -15   /* Already connected.       */\r\n\r\n#define ESPCONN_HANDSHAKE  -28   /* ssl handshake failed     */\r\n#define ESPCONN_SSL_INVALID_DATA  -61   /* ssl application invalid   */\r\n\r\n/** Protocol family and type of the espconn */\r\nenum espconn_type {\r\n    ESPCONN_INVALID    = 0,\r\n    /* ESPCONN_TCP Group */\r\n    ESPCONN_TCP        = 0x10,\r\n    /* ESPCONN_UDP Group */\r\n    ESPCONN_UDP        = 0x20,\r\n};\r\n\r\n/** Current state of the espconn. Non-TCP espconn are always in state ESPCONN_NONE! */\r\nenum espconn_state {\r\n    ESPCONN_NONE,\r\n    ESPCONN_WAIT,\r\n    ESPCONN_LISTEN,\r\n    ESPCONN_CONNECT,\r\n    ESPCONN_WRITE,\r\n    ESPCONN_READ,\r\n    ESPCONN_CLOSE\r\n};\r\n\r\ntypedef struct _esp_tcp {\r\n    int remote_port;\r\n    int local_port;\r\n    uint8 local_ip[4];\r\n    uint8 remote_ip[4];\r\n    espconn_connect_callback connect_callback;\r\n    espconn_reconnect_callback reconnect_callback;\r\n    espconn_connect_callback disconnect_callback;\r\n    espconn_connect_callback write_finish_fn;\r\n} esp_tcp;\r\n\r\ntypedef struct _esp_udp {\r\n    int remote_port;\r\n    int local_port;\r\n    uint8 local_ip[4];\r\n    uint8 remote_ip[4];\r\n} esp_udp;\r\n\r\ntypedef struct _remot_info{\r\n    enum espconn_state state;\r\n    int remote_port;\r\n    uint8 remote_ip[4];\r\n}remot_info;\r\n\r\n/** A callback prototype to inform about events for a espconn */\r\ntypedef void (* espconn_recv_callback)(void *arg, char *pdata, unsigned short len);\r\ntypedef void (* espconn_sent_callback)(void *arg);\r\n\r\n/** A espconn descriptor */\r\nstruct espconn {\r\n    /** type of the espconn (TCP, UDP) */\r\n    enum espconn_type type;\r\n    /** current state of the espconn */\r\n    enum espconn_state state;\r\n    union {\r\n        esp_tcp *tcp;\r\n        esp_udp *udp;\r\n    } proto;\r\n    /** A callback function that is informed about events for this espconn */\r\n    espconn_recv_callback recv_callback;\r\n    espconn_sent_callback sent_callback;\r\n    uint8 link_cnt;\r\n    void *reverse;\r\n};\r\n\r\nenum espconn_option{\r\n    ESPCONN_START = 0x00,\r\n    ESPCONN_REUSEADDR = 0x01,\r\n    ESPCONN_NODELAY = 0x02,\r\n    ESPCONN_COPY = 0x04,\r\n    ESPCONN_KEEPALIVE = 0x08,\r\n    ESPCONN_END\r\n};\r\n\r\nenum espconn_level{\r\n    ESPCONN_KEEPIDLE,\r\n    ESPCONN_KEEPINTVL,\r\n    ESPCONN_KEEPCNT\r\n};\r\n\r\nenum {\r\n    ESPCONN_IDLE = 0,\r\n    ESPCONN_CLIENT,\r\n    ESPCONN_SERVER,\r\n    ESPCONN_BOTH,\r\n    ESPCONN_MAX\r\n};\r\n\r\nstruct espconn_packet{\r\n    uint16 sent_length;     /* sent length successful*/\r\n    uint16 snd_buf_size;    /* Available buffer size for sending  */\r\n    uint16 snd_queuelen;    /* Available buffer space for sending */\r\n    uint16 total_queuelen;  /* total Available buffer space for sending */\r\n    uint32 packseqno;       /* seqno to be sent */\r\n    uint32 packseq_nxt;     /* seqno expected */\r\n    uint32 packnum;\r\n};\r\n\r\nstruct mdns_info {\r\n    char *host_name;\r\n    char *server_name;\r\n    uint16 server_port;\r\n    unsigned long ipAddr;\r\n    char *txt_data[10];\r\n};\r\n/******************************************************************************\r\n * FunctionName : espconn_connect\r\n * Description  : The function given as the connect\r\n * Parameters   : espconn -- the espconn used to listen the connection\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_connect(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_disconnect\r\n * Description  : disconnect with host\r\n * Parameters   : espconn -- the espconn used to disconnect the connection\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_disconnect(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_delete\r\n * Description  : disconnect with host\r\n * Parameters   : espconn -- the espconn used to disconnect the connection\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_delete(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_accept\r\n * Description  : The function given as the listen\r\n * Parameters   : espconn -- the espconn used to listen the connection\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_accept(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_create\r\n * Description  : sent data for client or server\r\n * Parameters   : espconn -- espconn to the data transmission\r\n * Returns      : result\r\n*******************************************************************************/\r\n\r\nsint8 espconn_create(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_tcp_get_max_con\r\n * Description  : get the number of simulatenously active TCP connections\r\n * Parameters   : none\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nuint8 espconn_tcp_get_max_con(void);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_tcp_set_max_con\r\n * Description  : set the number of simulatenously active TCP connections\r\n * Parameters   : num -- total number\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_tcp_set_max_con(uint8 num);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_tcp_get_max_con_allow\r\n * Description  : get the count of simulatenously active connections on the server\r\n * Parameters   : espconn -- espconn to get the count\r\n * Returns      : result\r\n*******************************************************************************/\r\n\r\nsint8 espconn_tcp_get_max_con_allow(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_tcp_set_max_con_allow\r\n * Description  : set the count of simulatenously active connections on the server\r\n * Parameters   : espconn -- espconn to set the count\r\n *                num -- support the connection number\r\n * Returns      : result\r\n*******************************************************************************/\r\n\r\nsint8 espconn_tcp_set_max_con_allow(struct espconn *espconn, uint8 num);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_regist_time\r\n * Description  : used to specify the time that should be called when don't recv data\r\n * Parameters   : espconn -- the espconn used to the connection\r\n *                interval -- the timer when don't recv data\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_regist_time(struct espconn *espconn, uint32 interval, uint8 type_flag);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_get_connection_info\r\n * Description  : used to specify the function that should be called when disconnect\r\n * Parameters   : espconn -- espconn to set the err callback\r\n *                discon_cb -- err callback function to call when err\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_get_connection_info(struct espconn *pespconn, remot_info **pcon_info, uint8 typeflags);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_get_packet_info\r\n * Description  : get the packet info with host\r\n * Parameters   : espconn -- the espconn used to disconnect the connection\r\n *                infoarg -- the packet info\r\n * Returns      : the errur code\r\n*******************************************************************************/\r\n\r\nsint8 espconn_get_packet_info(struct espconn *espconn, struct espconn_packet* infoarg);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_regist_sentcb\r\n * Description  : Used to specify the function that should be called when data\r\n *                has been successfully delivered to the remote host.\r\n * Parameters   : struct espconn *espconn -- espconn to set the sent callback\r\n *                espconn_sent_callback sent_cb -- sent callback function to\r\n *                call for this espconn when data is successfully sent\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_regist_sentcb(struct espconn *espconn, espconn_sent_callback sent_cb);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_regist_sentcb\r\n * Description  : Used to specify the function that should be called when data\r\n *                has been successfully delivered to the remote host.\r\n * Parameters   : espconn -- espconn to set the sent callback\r\n *                sent_cb -- sent callback function to call for this espconn\r\n *                when data is successfully sent\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_regist_write_finish(struct espconn *espconn, espconn_connect_callback write_finish_fn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_send\r\n * Description  : sent data for client or server\r\n * Parameters   : espconn -- espconn to set for client or server\r\n *                psent -- data to send\r\n *                length -- length of data to send\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_send(struct espconn *espconn, uint8 *psent, uint16 length);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_sent\r\n * Description  : sent data for client or server\r\n * Parameters   : espconn -- espconn to set for client or server\r\n *                psent -- data to send\r\n *                length -- length of data to send\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_sent(struct espconn *espconn, uint8 *psent, uint16 length);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_sendto\r\n * Description  : send data for UDP\r\n * Parameters   : espconn -- espconn to set for UDP\r\n *                psent -- data to send\r\n *                length -- length of data to send\r\n * Returns      : error\r\n*******************************************************************************/\r\n\r\nsint16 espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_regist_connectcb\r\n * Description  : used to specify the function that should be called when\r\n *                connects to host.\r\n * Parameters   : espconn -- espconn to set the connect callback\r\n *                connect_cb -- connected callback function to call when connected\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_regist_connectcb(struct espconn *espconn, espconn_connect_callback connect_cb);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_regist_recvcb\r\n * Description  : used to specify the function that should be called when recv\r\n *                data from host.\r\n * Parameters   : espconn -- espconn to set the recv callback\r\n *                recv_cb -- recv callback function to call when recv data\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_regist_recvcb(struct espconn *espconn, espconn_recv_callback recv_cb);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_regist_reconcb\r\n * Description  : used to specify the function that should be called when connection\r\n *                because of err disconnect.\r\n * Parameters   : espconn -- espconn to set the err callback\r\n *                recon_cb -- err callback function to call when err\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_regist_reconcb(struct espconn *espconn, espconn_reconnect_callback recon_cb);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_regist_disconcb\r\n * Description  : used to specify the function that should be called when disconnect\r\n * Parameters   : espconn -- espconn to set the err callback\r\n *                discon_cb -- err callback function to call when err\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_regist_disconcb(struct espconn *espconn, espconn_connect_callback discon_cb);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_port\r\n * Description  : access port value for client so that we don't end up bouncing\r\n *                all connections at the same time .\r\n * Parameters   : none\r\n * Returns      : access port value\r\n*******************************************************************************/\r\n\r\nuint32 espconn_port(void);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_set_opt\r\n * Description  : access port value for client so that we don't end up bouncing\r\n *                all connections at the same time .\r\n * Parameters   : none\r\n * Returns      : access port value\r\n*******************************************************************************/\r\n\r\nsint8 espconn_set_opt(struct espconn *espconn, uint8 opt);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_clear_opt\r\n * Description  : clear the option for connections so that we don't end up bouncing\r\n *                all connections at the same time .\r\n * Parameters   : espconn -- the espconn used to set the connection\r\n *                opt -- the option for clear\r\n * Returns      : the result\r\n*******************************************************************************/\r\n\r\nsint8 espconn_clear_opt(struct espconn *espconn, uint8 opt);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_set_keepalive\r\n * Description  : access level value for connection so that we set the value for\r\n *                keep alive\r\n * Parameters   : espconn -- the espconn used to set the connection\r\n *                level -- the connection's level\r\n *                value -- the value of time(s)\r\n * Returns      : access port value\r\n*******************************************************************************/\r\n\r\nsint8 espconn_set_keepalive(struct espconn *espconn, uint8 level, void* optarg);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_get_keepalive\r\n * Description  : access level value for connection so that we get the value for\r\n *                keep alive\r\n * Parameters   : espconn -- the espconn used to get the connection\r\n *                level -- the connection's level\r\n * Returns      : access keep alive value\r\n*******************************************************************************/\r\n\r\nsint8 espconn_get_keepalive(struct espconn *espconn, uint8 level, void *optarg);\r\n\r\n/******************************************************************************\r\n * TypedefName : dns_found_callback\r\n * Description : Callback which is invoked when a hostname is found.\r\n * Parameters  : name -- pointer to the name that was looked up.\r\n *               ipaddr -- pointer to an ip_addr_t containing the IP address of\r\n *               the hostname, or NULL if the name could not be found (or on any\r\n *               other error).\r\n *               callback_arg -- a user-specified callback argument passed to\r\n *               dns_gethostbyname\r\n*******************************************************************************/\r\n\r\ntypedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_gethostbyname\r\n * Description  : Resolve a hostname (string) into an IP address.\r\n * Parameters   : pespconn -- espconn to resolve a hostname\r\n *                hostname -- the hostname that is to be queried\r\n *                addr -- pointer to a ip_addr_t where to store the address if \r\n *                it is already cached in the dns_table (only valid if ESPCONN_OK\r\n *                is returned!)\r\n *                found -- a callback function to be called on success, failure\r\n *                or timeout (only if ERR_INPROGRESS is returned!)\r\n * Returns      : err_t return code\r\n *                - ESPCONN_OK if hostname is a valid IP address string or the host\r\n *                  name is already in the local names table.\r\n *                - ESPCONN_INPROGRESS enqueue a request to be sent to the DNS server\r\n *                  for resolution if no errors are present.\r\n *                - ESPCONN_ARG: dns client not initialized or invalid hostname\r\n*******************************************************************************/\r\n\r\nerr_t espconn_gethostbyname(struct espconn *pespconn, const char *hostname, ip_addr_t *addr, dns_found_callback found);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_encry_connect\r\n * Description  : The function given as connection\r\n * Parameters   : espconn -- the espconn used to connect with the host\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_secure_connect(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_encry_disconnect\r\n * Description  : The function given as the disconnection\r\n * Parameters   : espconn -- the espconn used to disconnect with the host\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_secure_disconnect(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_send\r\n * Description  : sent data for client or server\r\n * Parameters   : espconn -- espconn to set for client or server\r\n *                psent -- data to send\r\n *                length -- length of data to send\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_secure_send(struct espconn *espconn, uint8 *psent, uint16 length);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_encry_sent\r\n * Description  : sent data for client or server\r\n * Parameters   : espconn -- espconn to set for client or server\r\n *                psent -- data to send\r\n *                length -- length of data to send\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_set_size\r\n * Description  : set the buffer size for client or server\r\n * Parameters   : level -- set for client or server\r\n *                1: client,2:server,3:client and server\r\n *                size -- buffer size\r\n * Returns      : true or false\r\n*******************************************************************************/\r\n\r\nbool espconn_secure_set_size(uint8 level, uint16 size);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_get_size\r\n * Description  : get buffer size for client or server\r\n * Parameters   : level -- set for client or server\r\n *                1: client,2:server,3:client and server\r\n * Returns      : buffer size for client or server\r\n*******************************************************************************/\r\n\r\nsint16 espconn_secure_get_size(uint8 level);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_ca_enable\r\n * Description  : enable the certificate authenticate and set the flash sector\r\n *                as client or server\r\n * Parameters   : level -- set for client or server\r\n *                1: client,2:server,3:client and server\r\n *                flash_sector -- flash sector for save certificate\r\n * Returns      : result true or false\r\n*******************************************************************************/\r\n\r\nbool espconn_secure_ca_enable(uint8 level, uint8 flash_sector );\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_ca_disable\r\n * Description  : disable the certificate authenticate  as client or server\r\n * Parameters   : level -- set for client or server\r\n *                1: client,2:server,3:client and server\r\n * Returns      : result true or false\r\n*******************************************************************************/\r\n\r\nbool espconn_secure_ca_disable(uint8 level);\r\n\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_cert_req_enable\r\n * Description  : enable the client certificate authenticate and set the flash sector\r\n *                as client or server\r\n * Parameters   : level -- set for client or server\r\n *                1: client,2:server,3:client and server\r\n *                flash_sector -- flash sector for save certificate\r\n * Returns      : result true or false\r\n*******************************************************************************/\r\n\r\nbool espconn_secure_cert_req_enable(uint8 level, uint8 flash_sector );\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_ca_disable\r\n * Description  : disable the client certificate authenticate  as client or server\r\n * Parameters   : level -- set for client or server\r\n *                1: client,2:server,3:client and server\r\n * Returns      : result true or false\r\n*******************************************************************************/\r\n\r\nbool espconn_secure_cert_req_disable(uint8 level);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_set_default_certificate\r\n * Description  : Load the certificates in memory depending on compile-time\r\n *                and user options.\r\n * Parameters   : certificate -- Load the certificate\r\n *                length -- Load the certificate length\r\n * Returns      : result true or false\r\n*******************************************************************************/\r\n\r\nbool espconn_secure_set_default_certificate(const uint8* certificate, uint16 length);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_set_default_private_key\r\n * Description  : Load the key in memory depending on compile-time\r\n *                and user options.\r\n * Parameters   : private_key -- Load the key\r\n *                length -- Load the key length\r\n * Returns      : result true or false\r\n*******************************************************************************/\r\n\r\nbool espconn_secure_set_default_private_key(const uint8* private_key, uint16 length);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_secure_accept\r\n * Description  : The function given as the listen\r\n * Parameters   : espconn -- the espconn used to listen the connection\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nsint8 espconn_secure_accept(struct espconn *espconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_igmp_join\r\n * Description  : join a multicast group\r\n * Parameters   : host_ip -- the ip address of udp server\r\n *                multicast_ip -- multicast ip given by user\r\n * Returns      : none\r\n*******************************************************************************/\r\nsint8 espconn_igmp_join(ip_addr_t *host_ip, ip_addr_t *multicast_ip);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_igmp_leave\r\n * Description  : leave a multicast group\r\n * Parameters   : host_ip -- the ip address of udp server\r\n *                multicast_ip -- multicast ip given by user\r\n * Returns      : none\r\n*******************************************************************************/\r\nsint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_recv_hold\r\n * Description  : hold tcp receive\r\n * Parameters   : espconn -- espconn to hold\r\n * Returns      : none\r\n*******************************************************************************/\r\nsint8 espconn_recv_hold(struct espconn *pespconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_recv_unhold\r\n * Description  : unhold tcp receive\r\n * Parameters   : espconn -- espconn to unhold\r\n * Returns      : none\r\n*******************************************************************************/\r\nsint8 espconn_recv_unhold(struct espconn *pespconn);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_init\r\n * Description  : register a device with mdns\r\n * Parameters   : ipAddr -- the ip address of device\r\n *                hostname -- the hostname of device\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nvoid espconn_mdns_init(struct mdns_info *info);\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_close\r\n * Description  : close a device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nvoid espconn_mdns_close(void);\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_server_register\r\n * Description  : register a device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid espconn_mdns_server_register(void);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_server_unregister\r\n * Description  : unregister a device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid espconn_mdns_server_unregister(void);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_get_servername\r\n * Description  : get server name of device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\n\r\nchar* espconn_mdns_get_servername(void);\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_set_servername\r\n * Description  : set server name of device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid espconn_mdns_set_servername(const char *name);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_set_hostname\r\n * Description  : set host name of device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid espconn_mdns_set_hostname(char *name);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_get_hostname\r\n * Description  : get host name of device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\nchar* espconn_mdns_get_hostname(void);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_disable\r\n * Description  : disable a device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid espconn_mdns_disable(void);\r\n\r\n/******************************************************************************\r\n * FunctionName : espconn_mdns_enable\r\n * Description  : disable a device with mdns\r\n * Parameters   : a\r\n * Returns      : none\r\n*******************************************************************************/\r\nvoid espconn_mdns_enable(void);\r\n/******************************************************************************\r\n * FunctionName : espconn_dns_setserver\r\n * Description  : Initialize one of the DNS servers.\r\n * Parameters   : numdns -- the index of the DNS server to set must\r\n *                be < DNS_MAX_SERVERS = 2\r\n *                dnsserver -- IP address of the DNS server to set\r\n *  Returns     : none\r\n*******************************************************************************/\r\nvoid espconn_dns_setserver(char numdns, ip_addr_t *dnsserver);\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "include/espnow.h",
    "content": "/*\n *  Copyright (C) 2015 -2018  Espressif System\n *\n */\n\n#ifndef __ESPNOW_H__\n#define __ESPNOW_H__\n\nenum esp_now_role {\n\tESP_NOW_ROLE_IDLE = 0,\n\tESP_NOW_ROLE_CONTROLLER,\n\tESP_NOW_ROLE_SLAVE,\n\tESP_NOW_ROLE_MAX,\n};\n\ntypedef void (*esp_now_recv_cb_t)(u8 *mac_addr, u8 *data, u8 len);\ntypedef void (*esp_now_send_cb_t)(u8 *mac_addr, u8 status);\n\nint esp_now_init(void);\nint esp_now_deinit(void);\n\nint esp_now_register_send_cb(esp_now_send_cb_t cb);\nint esp_now_unregister_send_cb(void);\n\nint esp_now_register_recv_cb(esp_now_recv_cb_t cb);\nint esp_now_unregister_recv_cb(void);\n\nint esp_now_send(u8 *da, u8 *data, int len);\n\nint esp_now_add_peer(u8 *mac_addr, u8 role, u8 channel, u8 *key, u8 key_len);\nint esp_now_del_peer(u8 *mac_addr);\n\nint esp_now_set_self_role(u8 role);\nint esp_now_get_self_role(void);\n\nint esp_now_set_peer_role(u8 *mac_addr, u8 role);\nint esp_now_get_peer_role(u8 *mac_addr);\n\nint esp_now_set_peer_channel(u8 *mac_addr, u8 channel);\nint esp_now_get_peer_channel(u8 *mac_addr);\n\nint esp_now_set_peer_key(u8 *mac_addr, u8 *key, u8 key_len);\nint esp_now_get_peer_key(u8 *mac_addr, u8 *key, u8 *key_len);\n\nu8 *esp_now_fetch_peer(bool restart);\n\nint esp_now_is_peer_exist(u8 *mac_addr);\n\nint esp_now_get_cnt_info(u8 *all_cnt, u8 *encrypt_cnt);\n\nint esp_now_set_kok(u8 *key, u8 len);\n\n#endif\n"
  },
  {
    "path": "include/ets_sys.h",
    "content": "/*\n * copyright (c) 2008 - 2011 Espressif System\n *\n * Define user specified Event signals and Task priorities here\n *\n */\n\n#ifndef _ETS_SYS_H\n#define _ETS_SYS_H\n\n#include \"c_types.h\"\n#include \"eagle_soc.h\"\n\ntypedef uint32_t ETSSignal;\ntypedef uint32_t ETSParam;\n\ntypedef struct ETSEventTag ETSEvent;\n\nstruct ETSEventTag {\n    ETSSignal sig;\n    ETSParam  par;\n};\n\ntypedef void (*ETSTask)(ETSEvent *e);\n\n/* timer related */\ntypedef uint32_t ETSHandle;\ntypedef void ETSTimerFunc(void *timer_arg);\n\ntypedef struct _ETSTIMER_ {\n    struct _ETSTIMER_    *timer_next;\n    uint32_t              timer_expire;\n    uint32_t              timer_period;\n    ETSTimerFunc         *timer_func;\n    void                 *timer_arg;\n} ETSTimer;\n\n/* interrupt related */\n#define ETS_SPI_INUM\t   2\n#define ETS_GPIO_INUM       4\n#define ETS_UART_INUM       5\n#define ETS_UART1_INUM      5\n#define ETS_FRC_TIMER1_INUM 9  /* use edge*/\n\n#define ETS_INTR_LOCK() \\\n    ets_intr_lock()\n\n#define ETS_INTR_UNLOCK() \\\n    ets_intr_unlock()\n\n#define ETS_FRC_TIMER1_INTR_ATTACH(func, arg) \\\n    ets_isr_attach(ETS_FRC_TIMER1_INUM, (func), (void *)(arg))\n\n#define ETS_GPIO_INTR_ATTACH(func, arg) \\\n    ets_isr_attach(ETS_GPIO_INUM, (func), (void *)(arg))\n\n#define ETS_UART_INTR_ATTACH(func, arg) \\\n    ets_isr_attach(ETS_UART_INUM, (func), (void *)(arg))\n\n#define ETS_SPI_INTR_ATTACH(func, arg) \\\n    ets_isr_attach(ETS_SPI_INUM, (func), (void *)(arg))\n\n#define ETS_INTR_ENABLE(inum) \\\n    ets_isr_unmask((1<<inum))\n\n#define ETS_INTR_DISABLE(inum) \\\n    ets_isr_mask((1<<inum))\n\n#define ETS_SPI_INTR_ENABLE() \\\n    ETS_INTR_ENABLE(ETS_SPI_INUM)\n\n#define ETS_UART_INTR_ENABLE() \\\n    ETS_INTR_ENABLE(ETS_UART_INUM)\n\n#define ETS_UART_INTR_DISABLE() \\\n    ETS_INTR_DISABLE(ETS_UART_INUM)\n\n#define ETS_FRC1_INTR_ENABLE() \\\n\tETS_INTR_ENABLE(ETS_FRC_TIMER1_INUM)\n\n#define ETS_FRC1_INTR_DISABLE() \\\n\tETS_INTR_DISABLE(ETS_FRC_TIMER1_INUM)\n\n#define ETS_GPIO_INTR_ENABLE() \\\n    ETS_INTR_ENABLE(ETS_GPIO_INUM)\n\n#define ETS_GPIO_INTR_DISABLE() \\\n    ETS_INTR_DISABLE(ETS_GPIO_INUM)\n\n#endif /* _ETS_SYS_H */\n"
  },
  {
    "path": "include/gpio.h",
    "content": "/*\n * copyright (c) Espressif System 2010\n *\n */\n\n#ifndef _GPIO_H_\n#define _GPIO_H_\n\n#define GPIO_PIN_ADDR(i) (GPIO_PIN0_ADDRESS + i*4)\n\n#define GPIO_ID_IS_PIN_REGISTER(reg_id) \\\n    ((reg_id >= GPIO_ID_PIN0) && (reg_id <= GPIO_ID_PIN(GPIO_PIN_COUNT-1)))\n\n#define GPIO_REGID_TO_PINIDX(reg_id) ((reg_id) - GPIO_ID_PIN0)\n\ntypedef enum {\n    GPIO_PIN_INTR_DISABLE = 0,\n    GPIO_PIN_INTR_POSEDGE = 1,\n    GPIO_PIN_INTR_NEGEDGE = 2,\n    GPIO_PIN_INTR_ANYEDGE = 3,\n    GPIO_PIN_INTR_LOLEVEL = 4,\n    GPIO_PIN_INTR_HILEVEL = 5\n} GPIO_INT_TYPE;\n\n#define GPIO_OUTPUT_SET(gpio_no, bit_value) \\\n    gpio_output_set(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no,0)\n#define GPIO_DIS_OUTPUT(gpio_no) \tgpio_output_set(0,0,0, 1<<gpio_no)\n#define GPIO_INPUT_GET(gpio_no)     ((gpio_input_get()>>gpio_no)&BIT0)\n\n/* GPIO interrupt handler, registered through gpio_intr_handler_register */\ntypedef void (* gpio_intr_handler_fn_t)(uint32 intr_mask, void *arg);\n\n\n/*\n * Initialize GPIO.  This includes reading the GPIO Configuration DataSet\n * to initialize \"output enables\" and pin configurations for each gpio pin.\n * Must be called once during startup.\n */\nvoid gpio_init(void);\n\n/*\n * Change GPIO pin output by setting, clearing, or disabling pins.\n * In general, it is expected that a bit will be set in at most one\n * of these masks.  If a bit is clear in all masks, the output state\n * remains unchanged.\n *\n * There is no particular ordering guaranteed; so if the order of\n * writes is significant, calling code should divide a single call\n * into multiple calls.\n */\nvoid gpio_output_set(uint32 set_mask,\n                     uint32 clear_mask,\n                     uint32 enable_mask,\n                     uint32 disable_mask);\n\n/*\n * Sample the value of GPIO input pins and returns a bitmask.\n */\nuint32 gpio_input_get(void);\n\n/*\n * Set the specified GPIO register to the specified value.\n * This is a very general and powerful interface that is not\n * expected to be used during normal operation.  It is intended\n * mainly for debug, or for unusual requirements.\n */\nvoid gpio_register_set(uint32 reg_id, uint32 value);\n\n/* Get the current value of the specified GPIO register. */\nuint32 gpio_register_get(uint32 reg_id);\n\n/*\n * Register an application-specific interrupt handler for GPIO pin\n * interrupts.  Once the interrupt handler is called, it will not\n * be called again until after a call to gpio_intr_ack.  Any GPIO\n * interrupts that occur during the interim are masked.\n *\n * The application-specific handler is called with a mask of\n * pending GPIO interrupts.  After processing pin interrupts, the\n * application-specific handler may wish to use gpio_intr_pending\n * to check for any additional pending interrupts before it returns.\n */\nvoid gpio_intr_handler_register(gpio_intr_handler_fn_t fn, void *arg);\n\n/* Determine which GPIO interrupts are pending. */\nuint32 gpio_intr_pending(void);\n\n/*\n * Acknowledge GPIO interrupts.\n * Intended to be called from the gpio_intr_handler_fn.\n */\nvoid gpio_intr_ack(uint32 ack_mask);\n\nvoid gpio_pin_wakeup_enable(uint32 i, GPIO_INT_TYPE intr_state);\n\nvoid gpio_pin_wakeup_disable();\n\nvoid gpio_pin_intr_state_set(uint32 i, GPIO_INT_TYPE intr_state);\n\n#endif // _GPIO_H_\n"
  },
  {
    "path": "include/ip_addr.h",
    "content": "#ifndef __IP_ADDR_H__\n#define __IP_ADDR_H__\n\n#include \"c_types.h\"\n\nstruct ip_addr {\n    uint32 addr;\n};\n\ntypedef struct ip_addr ip_addr_t;\n\nstruct ip_info {\n    struct ip_addr ip;\n    struct ip_addr netmask;\n    struct ip_addr gw;\n};\n\n#define IP4_ADDR(ipaddr, a,b,c,d) \\\n        (ipaddr)->addr = ((uint32)((d) & 0xff) << 24) | \\\n                         ((uint32)((c) & 0xff) << 16) | \\\n                         ((uint32)((b) & 0xff) << 8)  | \\\n                          (uint32)((a) & 0xff)\n\n/**\n * Determine if two address are on the same network.\n *\n * @arg addr1 IP address 1\n * @arg addr2 IP address 2\n * @arg mask network identifier mask\n * @return !0 if the network identifiers of both address match\n */\n#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \\\n        (mask)->addr) == \\\n        ((addr2)->addr & \\\n         (mask)->addr))\n\n/** Set an IP address given by the four byte-parts.\n    Little-endian version that prevents the use of htonl. */\n#define IP4_ADDR(ipaddr, a,b,c,d) \\\n        (ipaddr)->addr = ((uint32)((d) & 0xff) << 24) | \\\n                         ((uint32)((c) & 0xff) << 16) | \\\n                         ((uint32)((b) & 0xff) << 8)  | \\\n                          (uint32)((a) & 0xff)\n\n#define ip4_addr1(ipaddr) (((uint8*)(ipaddr))[0])\n#define ip4_addr2(ipaddr) (((uint8*)(ipaddr))[1])\n#define ip4_addr3(ipaddr) (((uint8*)(ipaddr))[2])\n#define ip4_addr4(ipaddr) (((uint8*)(ipaddr))[3])\n\n#define ip4_addr1_16(ipaddr) ((uint16)ip4_addr1(ipaddr))\n#define ip4_addr2_16(ipaddr) ((uint16)ip4_addr2(ipaddr))\n#define ip4_addr3_16(ipaddr) ((uint16)ip4_addr3(ipaddr))\n#define ip4_addr4_16(ipaddr) ((uint16)ip4_addr4(ipaddr))\n\n\n/** 255.255.255.255 */\n#define IPADDR_NONE         ((uint32)0xffffffffUL)\n/** 0.0.0.0 */\n#define IPADDR_ANY          ((uint32)0x00000000UL)\nuint32 ipaddr_addr(const char *cp);\n\n#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \\\n    ip4_addr2_16(ipaddr), \\\n    ip4_addr3_16(ipaddr), \\\n    ip4_addr4_16(ipaddr)\n\n#define IPSTR \"%d.%d.%d.%d\"\n\n#endif /* __IP_ADDR_H__ */\n"
  },
  {
    "path": "include/mem.h",
    "content": "#ifndef __MEM_H__\r\n#define __MEM_H__\r\n\r\n\r\n\r\n\r\n/* Note: check_memleak_debug_enable is a weak function inside SDK.\r\n * please copy following codes to user_main.c.\r\n#include \"mem.h\"\r\n\r\n\r\n\r\n\r\nbool ICACHE_FLASH_ATTR check_memleak_debug_enable(void)\r\n{\r\n    return MEMLEAK_DEBUG_ENABLE;\r\n}\r\n*/\r\n\r\n#ifndef MEMLEAK_DEBUG\r\n#define MEMLEAK_DEBUG_ENABLE\t0\r\n#define os_free(s)        vPortFree(s, \"\", 0)\r\n#define os_malloc(s)      pvPortMalloc(s, \"\", 0)\r\n#define os_calloc(s)      pvPortCalloc(s, \"\", 0);\r\n#define os_realloc(p, s)  pvPortRealloc(p, s, \"\", 0)\r\n#define os_zalloc(s)      pvPortZalloc(s, \"\", 0)\r\n#else\r\n#define MEMLEAK_DEBUG_ENABLE\t1\r\n\r\n#define os_free(s) \\\r\ndo{\\\r\n\tstatic const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;\t\\\r\n    vPortFree(s, mem_debug_file, __LINE__);\\\r\n}while(0)\r\n\r\n#define os_malloc(s)\t\\\r\n\t({\t\\\r\n\t\tstatic const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;\t\\\r\n\t\tpvPortMalloc(s, mem_debug_file, __LINE__);\t\\\r\n\t})\r\n\r\n#define os_calloc(s)\t\\\r\n\t({\t\\\r\n\t\tstatic const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;\t\\\r\n\t\tpvPortCalloc(s, mem_debug_file, __LINE__);\t\\\r\n\t})\r\n\r\n#define os_realloc(p, s)\t\\\r\n\t({\t\\\r\n\t\tstatic const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;\t\\\r\n\t\tpvPortRealloc(p, s, mem_debug_file, __LINE__);\t\\\r\n\t})\r\n\r\n#define os_zalloc(s)\t\\\r\n\t({\t\\\r\n\t\tstatic const char mem_debug_file[] ICACHE_RODATA_ATTR STORE_ATTR = __FILE__;\t\\\r\n\t\tpvPortZalloc(s, mem_debug_file, __LINE__);\t\\\r\n\t})\r\n\r\n#endif\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "include/mesh.h",
    "content": "#ifndef __LWIP_API_MESH_H__\n#define __LWIP_API_MESH_H__\n\n#include \"ip_addr.h\"\n#include \"user_interface.h\"\n#include \"espconn.h\"\n\ntypedef void (* espconn_mesh_callback)();\n\nenum mesh_type {\n\tMESH_CLOSE = 0,\n    MESH_LOCAL,\n    MESH_ONLINE,\n    MESH_NONE = 0xFF\n};\n\nenum mesh_status {\n    MESH_DISABLE = 0,\n    MESH_WIFI_CONN,\n    MESH_NET_CONN,\n    MESH_LOCAL_AVAIL,\n    MESH_ONLINE_AVAIL\n};\n\nenum mesh_node_type {\n\tMESH_NODE_PARENT = 0,\n\tMESH_NODE_CHILD,\n\tMESH_NODE_ALL\n};\n\nbool espconn_mesh_local_addr(struct ip_addr *ip);\nbool espconn_mesh_get_node_info(enum mesh_node_type type,\n\t\t                        uint8_t **info, uint8_t *count);\nbool espconn_mesh_get_router(struct station_config *router);\nbool espconn_mesh_set_router(struct station_config *router);\nbool espconn_mesh_encrypt_init(AUTH_MODE mode, uint8_t *passwd, uint8_t passwd_len);\nbool espconn_mesh_set_ssid_prefix(uint8_t *prefix, uint8_t prefix_len);\nbool espconn_mesh_set_max_hops(uint8_t max_hops);\n\nchar * espconn_json_find_section(const char *pbuf, u16 len, const char *section);\n\nsint8 espconn_mesh_connect(struct espconn *usr_esp);\nsint8 espconn_mesh_disconnect(struct espconn *usr_esp);\nsint8 espconn_mesh_get_status();\nsint8 espconn_mesh_sent(struct espconn *usr_esp, uint8 *pdata, uint16 len);\n\nuint8 espconn_mesh_get_max_hops();\nuint8 espconn_mesh_layer(struct ip_addr *ip);\nuint32_t user_json_get_value(const char *pbuffer, uint16_t buf_len,\n\t\t                     const uint8_t *json_key);\n\nvoid espconn_mesh_enable(espconn_mesh_callback enable_cb, enum mesh_type type);\nvoid espconn_mesh_disable(espconn_mesh_callback disable_cb);\nvoid espconn_mesh_init();\nvoid espconn_mesh_init_group_list(uint8_t *dev_mac, uint16_t dev_count);\nvoid espconn_mesh_set_dev_type(uint8_t dev_type);\nvoid espconn_mesh_setup_timer(os_timer_t *timer, uint32_t time,\n                              os_timer_func_t cb, void *arg, bool repeat);\n\n#endif\n\n"
  },
  {
    "path": "include/os_type.h",
    "content": "/*\r\n * copyright (c) Espressif System 2010\r\n *\r\n * mapping to ETS structures\r\n *\r\n */\r\n#ifndef _OS_TYPES_H_\r\n#define _OS_TYPES_H_\r\n\r\n#include \"ets_sys.h\"\r\n\r\n#define os_signal_t ETSSignal\r\n#define os_param_t  ETSParam\r\n#define os_event_t ETSEvent\r\n#define os_task_t ETSTask\r\n#define os_timer_t  ETSTimer\r\n#define os_timer_func_t ETSTimerFunc\r\n\r\n#endif\r\n"
  },
  {
    "path": "include/osapi.h",
    "content": "/*\r\n * Copyright (c) 2010 Espressif System\r\n */\r\n\r\n#ifndef _OSAPI_H_\r\n#define _OSAPI_H_\r\n\r\n#include <string.h>\r\n#include \"user_config.h\"\r\n\r\n#define os_bzero ets_bzero\r\n#define os_delay_us ets_delay_us\r\n#define os_install_putc1 ets_install_putc1\r\n\r\n#define os_memcmp ets_memcmp\r\n#define os_memcpy ets_memcpy\r\n#define os_memmove ets_memmove\r\n#define os_memset ets_memset\r\n#define os_strcat strcat\r\n#define os_strchr strchr\r\n#define os_strcmp ets_strcmp\r\n#define os_strcpy ets_strcpy\r\n#define os_strlen ets_strlen\r\n#define os_strncmp ets_strncmp\r\n#define os_strncpy ets_strncpy\r\n#define os_strstr ets_strstr\r\n#ifdef USE_US_TIMER\r\n#define os_timer_arm_us(a, b, c) ets_timer_arm_new(a, b, c, 0)\r\n#endif\r\n#define os_timer_arm(a, b, c) ets_timer_arm_new(a, b, c, 1)\r\n#define os_timer_disarm ets_timer_disarm\r\n#define os_timer_setfn ets_timer_setfn\r\n\r\n#define os_sprintf  ets_sprintf\r\n\r\n#ifdef USE_OPTIMIZE_PRINTF\r\n#define os_printf(fmt, ...) do {\t\\\r\n\tstatic const char flash_str[] ICACHE_RODATA_ATTR STORE_ATTR = fmt;\t\\\r\n\tos_printf_plus(flash_str, ##__VA_ARGS__);\t\\\r\n\t} while(0)\r\n#else\r\n#define os_printf\tos_printf_plus\r\n#endif\r\n\r\nunsigned long os_random(void);\r\nint os_get_random(unsigned char *buf, size_t len);\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "include/ping.h",
    "content": "#ifndef __PING_H__\n#define __PING_H__\n\n\ntypedef void (* ping_recv_function)(void* arg, void *pdata);\ntypedef void (* ping_sent_function)(void* arg, void *pdata);\n\nstruct ping_option{\n\tuint32 count;\n\tuint32 ip;\n\tuint32 coarse_time;\n\tping_recv_function recv_function;\n\tping_sent_function sent_function;\n\tvoid* reverse;\n};\n\nstruct ping_resp{\n\tuint32 total_count;\n\tuint32 resp_time;\n\tuint32 seqno;\n\tuint32 timeout_count;\n\tuint32 bytes;\n\tuint32 total_bytes;\n\tuint32 total_time;\n\tsint8  ping_err;\n};\n\nbool ping_start(struct ping_option *ping_opt);\nbool ping_regist_recv(struct ping_option *ping_opt, ping_recv_function ping_recv);\nbool ping_regist_sent(struct ping_option *ping_opt, ping_sent_function ping_sent);\n\n#endif /* __PING_H__ */\n"
  },
  {
    "path": "include/pwm.h",
    "content": "#ifndef __PWM_H__\r\n#define __PWM_H__\r\n\r\n/*pwm.h: function and macro definition of PWM API , driver level */\r\n/*user_light.h: user interface for light API, user level*/\r\n/*user_light_adj: API for color changing and lighting effects, user level*/\r\n\r\n\r\n /*NOTE!!  : DO NOT CHANGE THIS FILE*/\r\n\r\n /*SUPPORT UP TO 8 PWM CHANNEL*/\r\n#define PWM_CHANNEL_NUM_MAX 8 \r\n\r\nstruct pwm_param {\r\n    uint32 period;\r\n    uint32 freq;\r\n    uint32  duty[PWM_CHANNEL_NUM_MAX];  //PWM_CHANNEL<=8\r\n};\r\n\r\n\r\n/* pwm_init should be called only once, for now  */\r\nvoid pwm_init(uint32 period, uint32 *duty,uint32 pwm_channel_num,uint32 (*pin_info_list)[3]);\r\nvoid pwm_start(void);\r\n\r\nvoid pwm_set_duty(uint32 duty, uint8 channel);\r\nuint32 pwm_get_duty(uint8 channel);\r\nvoid pwm_set_period(uint32 period);\r\nuint32 pwm_get_period(void);\r\n\r\nuint32 get_pwm_version(void);\r\nvoid set_pwm_debug_en(uint8 print_en);\r\n\r\n#endif\r\n\r\n"
  },
  {
    "path": "include/queue.h",
    "content": "#ifndef _SYS_QUEUE_H_\n#define\t_SYS_QUEUE_H_\n\n#define\tQMD_SAVELINK(name, link)\n#define\tTRASHIT(x)\n\n/*\n * Singly-linked List declarations.\n */\n#define\tSLIST_HEAD(name, type)\t\t\t\t\t\t\\\nstruct name {\t\t\t\t\t\t\t\t\\\n\tstruct type *slh_first;\t/* first element */\t\t\t\\\n}\n\n#define\tSLIST_HEAD_INITIALIZER(head)\t\t\t\t\t\\\n\t{ NULL }\n\n#define\tSLIST_ENTRY(type)\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\tstruct type *sle_next;\t/* next element */\t\t\t\\\n}\n\n/*\n * Singly-linked List functions.\n */\n#define\tSLIST_EMPTY(head)\t((head)->slh_first == NULL)\n\n#define\tSLIST_FIRST(head)\t((head)->slh_first)\n\n#define\tSLIST_FOREACH(var, head, field)\t\t\t\t\t\\\n\tfor ((var) = SLIST_FIRST((head));\t\t\t\t\\\n\t    (var);\t\t\t\t\t\t\t\\\n\t    (var) = SLIST_NEXT((var), field))\n\n#define\tSLIST_FOREACH_SAFE(var, head, field, tvar)\t\t\t\\\n\tfor ((var) = SLIST_FIRST((head));\t\t\t\t\\\n\t    (var) && ((tvar) = SLIST_NEXT((var), field), 1);\t\t\\\n\t    (var) = (tvar))\n\n#define\tSLIST_FOREACH_PREVPTR(var, varp, head, field)\t\t\t\\\n\tfor ((varp) = &SLIST_FIRST((head));\t\t\t\t\\\n\t    ((var) = *(varp)) != NULL;\t\t\t\t\t\\\n\t    (varp) = &SLIST_NEXT((var), field))\n\n#define\tSLIST_INIT(head) do {\t\t\t\t\t\t\\\n\tSLIST_FIRST((head)) = NULL;\t\t\t\t\t\\\n} while (0)\n\n#define\tSLIST_INSERT_AFTER(slistelm, elm, field) do {\t\t\t\\\n\tSLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);\t\\\n\tSLIST_NEXT((slistelm), field) = (elm);\t\t\t\t\\\n} while (0)\n\n#define\tSLIST_INSERT_HEAD(head, elm, field) do {\t\t\t\\\n\tSLIST_NEXT((elm), field) = SLIST_FIRST((head));\t\t\t\\\n\tSLIST_FIRST((head)) = (elm);\t\t\t\t\t\\\n} while (0)\n\n#define\tSLIST_NEXT(elm, field)\t((elm)->field.sle_next)\n\n#define\tSLIST_REMOVE(head, elm, type, field) do {\t\t\t\\\n\tQMD_SAVELINK(oldnext, (elm)->field.sle_next);\t\t\t\\\n\tif (SLIST_FIRST((head)) == (elm)) {\t\t\t\t\\\n\t\tSLIST_REMOVE_HEAD((head), field);\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\telse {\t\t\t\t\t\t\t\t\\\n\t\tstruct type *curelm = SLIST_FIRST((head));\t\t\\\n\t\twhile (SLIST_NEXT(curelm, field) != (elm))\t\t\\\n\t\t\tcurelm = SLIST_NEXT(curelm, field);\t\t\\\n\t\tSLIST_REMOVE_AFTER(curelm, field);\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tTRASHIT(*oldnext);\t\t\t\t\t\t\\\n} while (0)\n\n#define SLIST_REMOVE_AFTER(elm, field) do {\t\t\t\t\\\n\tSLIST_NEXT(elm, field) =\t\t\t\t\t\\\n\t    SLIST_NEXT(SLIST_NEXT(elm, field), field);\t\t\t\\\n} while (0)\n\n#define\tSLIST_REMOVE_HEAD(head, field) do {\t\t\t\t\\\n\tSLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);\t\\\n} while (0)\n\n/*\n * Singly-linked Tail queue declarations.\n */\n#define\tSTAILQ_HEAD(name, type)\t\t\t\t\t\t\\\n    struct name {\t\t\t\t\t\t\t\t\\\n        struct type *stqh_first;/* first element */\t\t\t\\\n        struct type **stqh_last;/* addr of last next element */\t\t\\\n    }\n\n#define\tSTAILQ_HEAD_INITIALIZER(head)\t\t\t\t\t\\\n    { NULL, &(head).stqh_first }\n\n#define\tSTAILQ_ENTRY(type)\t\t\t\t\t\t\\\n    struct {\t\t\t\t\t\t\t\t\\\n        struct type *stqe_next;\t/* next element */\t\t\t\\\n    }\n\n/*\n * Singly-linked Tail queue functions.\n */\n#define\tSTAILQ_CONCAT(head1, head2) do {\t\t\t\t\\\n        if (!STAILQ_EMPTY((head2))) {\t\t\t\t\t\\\n            *(head1)->stqh_last = (head2)->stqh_first;\t\t\\\n            (head1)->stqh_last = (head2)->stqh_last;\t\t\\\n            STAILQ_INIT((head2));\t\t\t\t\t\\\n        }\t\t\t\t\t\t\t\t\\\n    } while (0)\n\n#define\tSTAILQ_EMPTY(head)\t((head)->stqh_first == NULL)\n\n#define\tSTAILQ_FIRST(head)\t((head)->stqh_first)\n\n#define\tSTAILQ_FOREACH(var, head, field)\t\t\t\t\\\n    for((var) = STAILQ_FIRST((head));\t\t\t\t\\\n            (var);\t\t\t\t\t\t\t\\\n            (var) = STAILQ_NEXT((var), field))\n\n\n#define\tSTAILQ_FOREACH_SAFE(var, head, field, tvar)\t\t\t\\\n    for ((var) = STAILQ_FIRST((head));\t\t\t\t\\\n            (var) && ((tvar) = STAILQ_NEXT((var), field), 1);\t\t\\\n            (var) = (tvar))\n\n#define\tSTAILQ_INIT(head) do {\t\t\t\t\t\t\\\n        STAILQ_FIRST((head)) = NULL;\t\t\t\t\t\\\n        (head)->stqh_last = &STAILQ_FIRST((head));\t\t\t\\\n    } while (0)\n\n#define\tSTAILQ_INSERT_AFTER(head, tqelm, elm, field) do {\t\t\\\n        if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\\\n            (head)->stqh_last = &STAILQ_NEXT((elm), field);\t\t\\\n        STAILQ_NEXT((tqelm), field) = (elm);\t\t\t\t\\\n    } while (0)\n\n#define\tSTAILQ_INSERT_HEAD(head, elm, field) do {\t\t\t\\\n        if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)\t\\\n            (head)->stqh_last = &STAILQ_NEXT((elm), field);\t\t\\\n        STAILQ_FIRST((head)) = (elm);\t\t\t\t\t\\\n    } while (0)\n\n#define\tSTAILQ_INSERT_TAIL(head, elm, field) do {\t\t\t\\\n        STAILQ_NEXT((elm), field) = NULL;\t\t\t\t\\\n        *(head)->stqh_last = (elm);\t\t\t\t\t\\\n        (head)->stqh_last = &STAILQ_NEXT((elm), field);\t\t\t\\\n    } while (0)\n\n#define\tSTAILQ_LAST(head, type, field)\t\t\t\t\t\\\n    (STAILQ_EMPTY((head)) ?\t\t\t\t\t\t\\\n     NULL :\t\t\t\t\t\t\t\\\n     ((struct type *)(void *)\t\t\t\t\\\n      ((char *)((head)->stqh_last) - __offsetof(struct type, field))))\n\n#define\tSTAILQ_NEXT(elm, field)\t((elm)->field.stqe_next)\n\n#define\tSTAILQ_REMOVE(head, elm, type, field) do {\t\t\t\\\n        QMD_SAVELINK(oldnext, (elm)->field.stqe_next);\t\t\t\\\n        if (STAILQ_FIRST((head)) == (elm)) {\t\t\t\t\\\n            STAILQ_REMOVE_HEAD((head), field);\t\t\t\\\n        }\t\t\t\t\t\t\t\t\\\n        else {\t\t\t\t\t\t\t\t\\\n            struct type *curelm = STAILQ_FIRST((head));\t\t\\\n            while (STAILQ_NEXT(curelm, field) != (elm))\t\t\\\n                curelm = STAILQ_NEXT(curelm, field);\t\t\\\n            STAILQ_REMOVE_AFTER(head, curelm, field);\t\t\\\n        }\t\t\t\t\t\t\t\t\\\n        TRASHIT(*oldnext);\t\t\t\t\t\t\\\n    } while (0)\n\n#define\tSTAILQ_REMOVE_HEAD(head, field) do {\t\t\t\t\\\n        if ((STAILQ_FIRST((head)) =\t\t\t\t\t\\\n                STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)\t\t\\\n            (head)->stqh_last = &STAILQ_FIRST((head));\t\t\\\n    } while (0)\n\n#define STAILQ_REMOVE_AFTER(head, elm, field) do {\t\t\t\\\n        if ((STAILQ_NEXT(elm, field) =\t\t\t\t\t\\\n                STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL)\t\\\n            (head)->stqh_last = &STAILQ_NEXT((elm), field);\t\t\\\n    } while (0)\n\n#define STAILQ_SWAP(head1, head2, type) do {\t\t\t\t\\\n        struct type *swap_first = STAILQ_FIRST(head1);\t\t\t\\\n        struct type **swap_last = (head1)->stqh_last;\t\t\t\\\n        STAILQ_FIRST(head1) = STAILQ_FIRST(head2);\t\t\t\\\n        (head1)->stqh_last = (head2)->stqh_last;\t\t\t\\\n        STAILQ_FIRST(head2) = swap_first;\t\t\t\t\\\n        (head2)->stqh_last = swap_last;\t\t\t\t\t\\\n        if (STAILQ_EMPTY(head1))\t\t\t\t\t\\\n            (head1)->stqh_last = &STAILQ_FIRST(head1);\t\t\\\n        if (STAILQ_EMPTY(head2))\t\t\t\t\t\\\n            (head2)->stqh_last = &STAILQ_FIRST(head2);\t\t\\\n    } while (0)\n\n#define STAILQ_INSERT_CHAIN_HEAD(head, elm_chead, elm_ctail, field) do {   \\\n        if ((STAILQ_NEXT(elm_ctail, field) = STAILQ_FIRST(head)) == NULL ) { \\\n            (head)->stqh_last = &STAILQ_NEXT(elm_ctail, field);            \\\n        }                                                                      \\\n        STAILQ_FIRST(head) = (elm_chead);                                    \\\n    } while (0)\n\n#endif /* !_SYS_QUEUE_H_ */\n"
  },
  {
    "path": "include/smartconfig.h",
    "content": "/*\n *  Copyright (C) 2015 -2018  Espressif System\n *\n */\n\n#ifndef __SMARTCONFIG_H__\n#define __SMARTCONFIG_H__\n\ntypedef enum {\n    SC_STATUS_WAIT = 0,\n    SC_STATUS_FIND_CHANNEL,\n    SC_STATUS_GETTING_SSID_PSWD,\n    SC_STATUS_LINK,\n    SC_STATUS_LINK_OVER,\n} sc_status;\n\ntypedef enum {\n    SC_TYPE_ESPTOUCH = 0,\n    SC_TYPE_AIRKISS,\n\tSC_TYPE_ESPTOUCH_AIRKISS,\n} sc_type;\n\ntypedef void (*sc_callback_t)(sc_status status, void *pdata);\n\nconst char *smartconfig_get_version(void);\nbool smartconfig_start(sc_callback_t cb, ...);\nbool smartconfig_stop(void);\nbool esptouch_set_timeout(uint8 time_s); //15s~255s, offset:45s\nbool smartconfig_set_type(sc_type type);\n\n#endif\n"
  },
  {
    "path": "include/sntp.h",
    "content": "#ifndef __SNTP_H__\n#define __SNTP_H__\n\n#include \"os_type.h\"\n#ifdef LWIP_OPEN_SRC\n#include \"lwip/ip_addr.h\"\n#else\n#include \"ip_addr.h\"\n#endif\n/**\n * get the seconds since Jan 01, 1970, 00:00 (GMT + 8)\n */\nuint32 sntp_get_current_timestamp();\n/**\n * get real time (GTM + 8 time zone)\n */\nchar* sntp_get_real_time(long t);\n/**\n * SNTP get time_zone default GMT + 8\n */\nsint8 sntp_get_timezone(void);\n/**\n * SNTP set time_zone (default GMT + 8)\n */\nbool sntp_set_timezone(sint8 timezone);\n/**\n * Initialize this module.\n * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC).\n */\nvoid sntp_init(void);\n/**\n * Stop this module.\n */\nvoid sntp_stop(void);\n/**\n * Initialize one of the NTP servers by IP address\n *\n * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS\n * @param dnsserver IP address of the NTP server to set\n */\nvoid sntp_setserver(unsigned char idx, ip_addr_t *addr);\n/**\n * Obtain one of the currently configured by IP address (or DHCP) NTP servers\n *\n * @param numdns the index of the NTP server\n * @return IP address of the indexed NTP server or \"ip_addr_any\" if the NTP\n *         server has not been configured by address (or at all).\n */\nip_addr_t sntp_getserver(unsigned char idx);\n/**\n * Initialize one of the NTP servers by name\n *\n * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS,now sdk support SNTP_MAX_SERVERS = 3\n * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time\n */\nvoid sntp_setservername(unsigned char idx, char *server);\n/**\n * Obtain one of the currently configured by name NTP servers.\n *\n * @param numdns the index of the NTP server\n * @return IP address of the indexed NTP server or NULL if the NTP\n *         server has not been configured by name (or at all)\n */\nchar *sntp_getservername(unsigned char idx);\n\n#define sntp_servermode_dhcp(x)\n\n#endif\n"
  },
  {
    "path": "include/spi_flash.h",
    "content": "/* \n * copyright (c) Espressif System 2010\n * \n */\n\n#ifndef SPI_FLASH_H\n#define SPI_FLASH_H\n\ntypedef enum {\n    SPI_FLASH_RESULT_OK,\n    SPI_FLASH_RESULT_ERR,\n    SPI_FLASH_RESULT_TIMEOUT\n} SpiFlashOpResult;\n\ntypedef struct{\n\tuint32\tdeviceId;\n\tuint32\tchip_size;    // chip size in byte\n\tuint32\tblock_size;\n\tuint32  sector_size;\n\tuint32  page_size;\n\tuint32  status_mask;\n} SpiFlashChip;\n\n#define SPI_FLASH_SEC_SIZE      4096\n\nuint32 spi_flash_get_id(void);\nSpiFlashOpResult spi_flash_erase_sector(uint16 sec);\nSpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size);\nSpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 *des_addr, uint32 size);\n\ntypedef SpiFlashOpResult (* user_spi_flash_read)(\n\t\tSpiFlashChip *spi,\n\t\tuint32 src_addr,\n\t\tuint32 *des_addr,\n        uint32 size);\n\nvoid spi_flash_set_read_func(user_spi_flash_read read);\n\n#endif\n"
  },
  {
    "path": "include/upgrade.h",
    "content": "#ifndef __UPGRADE_H__\n#define __UPGRADE_H__\n\n#define SPI_FLASH_SEC_SIZE      4096\n\n#define USER_BIN1               0x00\n#define USER_BIN2               0x01\n\n#define UPGRADE_FLAG_IDLE       0x00\n#define UPGRADE_FLAG_START      0x01\n#define UPGRADE_FLAG_FINISH     0x02\n\n#define UPGRADE_FW_BIN1         0x00\n#define UPGRADE_FW_BIN2         0x01\n\ntypedef void (*upgrade_states_check_callback)(void * arg);\n\n//#define UPGRADE_SSL_ENABLE\n\nstruct upgrade_server_info {\n    uint8 ip[4];\n    uint16 port;\n\n    uint8 upgrade_flag;\n\n    uint8 pre_version[16];\n    uint8 upgrade_version[16];\n\n    uint32 check_times;\n    uint8 *url;\n\n    upgrade_states_check_callback check_cb;\n    struct espconn *pespconn;\n};\n\n#define UPGRADE_FLAG_IDLE       0x00\n#define UPGRADE_FLAG_START      0x01\n#define UPGRADE_FLAG_FINISH     0x02\n\n//bool system_upgrade_start(struct upgrade_server_info *server);\nbool system_upgrade_start_ssl(struct upgrade_server_info *server);\nvoid system_upgrade_init();\nvoid system_upgrade_deinit();\nbool system_upgrade(uint8 *data, uint16 len);\n\n#ifdef UPGRADE_SSL_ENABLE\nbool system_upgrade_start_ssl(struct upgrade_server_info *server);\n#else\nbool system_upgrade_start(struct upgrade_server_info *server);\n#endif\n#endif\n"
  },
  {
    "path": "include/user_interface.h",
    "content": "/*\r\n *  Copyright (C) 2013 -2014  Espressif System\r\n *\r\n */\r\n\r\n#ifndef __USER_INTERFACE_H__\r\n#define __USER_INTERFACE_H__\r\n\r\n#include \"os_type.h\"\r\n#ifdef LWIP_OPEN_SRC\r\n#include \"lwip/ip_addr.h\"\r\n#else\r\n#include \"ip_addr.h\"\r\n#endif\r\n\r\n#include \"queue.h\"\r\n#include \"user_config.h\"\r\n#include \"spi_flash.h\"\r\n\r\n#ifndef MAC2STR\r\n#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]\r\n#define MACSTR \"%02x:%02x:%02x:%02x:%02x:%02x\"\r\n#endif\r\n\r\nenum rst_reason {\r\n    REASON_DEFAULT_RST      = 0,\r\n    REASON_WDT_RST          = 1,\r\n    REASON_EXCEPTION_RST    = 2,\r\n    REASON_SOFT_WDT_RST     = 3,\r\n    REASON_SOFT_RESTART     = 4,\r\n    REASON_DEEP_SLEEP_AWAKE = 5,\r\n    REASON_EXT_SYS_RST      = 6\r\n};\r\n\r\nstruct rst_info{\r\n    uint32 reason;\r\n    uint32 exccause;\r\n    uint32 epc1;\r\n    uint32 epc2;\r\n    uint32 epc3;\r\n    uint32 excvaddr;\r\n    uint32 depc;\r\n};\r\n\r\nstruct rst_info* system_get_rst_info(void);\r\n\r\n#define UPGRADE_FW_BIN1         0x00\r\n#define UPGRADE_FW_BIN2         0x01\r\n\r\nvoid system_restore(void);\r\nvoid system_restart(void);\r\n\r\nbool system_deep_sleep_set_option(uint8 option);\r\nvoid system_deep_sleep(uint32 time_in_us);\r\n\r\nuint8 system_upgrade_userbin_check(void);\r\nvoid system_upgrade_reboot(void);\r\nuint8 system_upgrade_flag_check();\r\nvoid system_upgrade_flag_set(uint8 flag);\r\n\r\nvoid system_timer_reinit(void);\r\nuint32 system_get_time(void);\r\n\r\n/* user task's prio must be 0/1/2 !!!*/\r\nenum {\r\n    USER_TASK_PRIO_0 = 0,\r\n    USER_TASK_PRIO_1,\r\n    USER_TASK_PRIO_2,\r\n    USER_TASK_PRIO_MAX\r\n};\r\n\r\nbool system_os_task(os_task_t task, uint8 prio, os_event_t *queue, uint8 qlen);\r\nbool system_os_post(uint8 prio, os_signal_t sig, os_param_t par);\r\n\r\nvoid system_print_meminfo(void);\r\nuint32 system_get_free_heap_size(void);\r\n\r\nvoid system_set_os_print(uint8 onoff);\r\nuint8 system_get_os_print();\r\n\r\nuint64 system_mktime(uint32 year, uint32 mon, uint32 day, uint32 hour, uint32 min, uint32 sec);\r\n\r\nuint32 system_get_chip_id(void);\r\n\r\ntypedef void (* init_done_cb_t)(void);\r\n\r\nvoid system_init_done_cb(init_done_cb_t cb);\r\n\r\nuint32 system_rtc_clock_cali_proc(void);\r\nuint32 system_get_rtc_time(void);\r\n\r\nbool system_rtc_mem_read(uint8 src_addr, void *des_addr, uint16 load_size);\r\nbool system_rtc_mem_write(uint8 des_addr, const void *src_addr, uint16 save_size);\r\n\r\nvoid system_uart_swap(void);\r\nvoid system_uart_de_swap(void);\r\n\r\nuint16 system_adc_read(void);\r\nuint16 system_get_vdd33(void);\r\n\r\nconst char *system_get_sdk_version(void);\r\n\r\n#define SYS_BOOT_ENHANCE_MODE   0\r\n#define SYS_BOOT_NORMAL_MODE    1\r\n\r\n#define SYS_BOOT_NORMAL_BIN     0\r\n#define SYS_BOOT_TEST_BIN       1\r\n\r\nuint8 system_get_boot_version(void);\r\nuint32 system_get_userbin_addr(void);\r\nuint8 system_get_boot_mode(void);\r\nbool system_restart_enhance(uint8 bin_type, uint32 bin_addr);\r\n\r\n#define SYS_CPU_80MHZ   80\r\n#define SYS_CPU_160MHZ  160\r\n\r\nbool system_update_cpu_freq(uint8 freq);\r\nuint8 system_get_cpu_freq(void);\r\n\r\nenum flash_size_map {\r\n    FLASH_SIZE_4M_MAP_256_256 = 0,\r\n    FLASH_SIZE_2M,\r\n    FLASH_SIZE_8M_MAP_512_512,\r\n    FLASH_SIZE_16M_MAP_512_512,\r\n    FLASH_SIZE_32M_MAP_512_512,\r\n    FLASH_SIZE_16M_MAP_1024_1024,\r\n    FLASH_SIZE_32M_MAP_1024_1024\r\n};\r\n\r\nenum flash_size_map system_get_flash_size_map(void);\r\n\r\nvoid system_phy_set_max_tpw(uint8 max_tpw);\r\nvoid system_phy_set_tpw_via_vdd33(uint16 vdd33);\r\nvoid system_phy_set_rfoption(uint8 option);\r\nvoid system_phy_set_powerup_option(uint8 option);\r\n\r\nbool system_param_save_with_protect(uint16 start_sec, void *param, uint16 len);\r\nbool system_param_load(uint16 start_sec, uint16 offset, void *param, uint16 len);\r\n\r\nvoid system_soft_wdt_stop(void);\r\nvoid system_soft_wdt_restart(void);\r\nvoid system_soft_wdt_feed(void);\r\n\r\nvoid system_show_malloc(void);\r\n\r\n#define NULL_MODE       0x00\r\n#define STATION_MODE    0x01\r\n#define SOFTAP_MODE     0x02\r\n#define STATIONAP_MODE  0x03\r\n\r\ntypedef enum _auth_mode {\r\n    AUTH_OPEN           = 0,\r\n    AUTH_WEP,\r\n    AUTH_WPA_PSK,\r\n    AUTH_WPA2_PSK,\r\n    AUTH_WPA_WPA2_PSK,\r\n    AUTH_MAX\r\n} AUTH_MODE;\r\n\r\nuint8 wifi_get_opmode(void);\r\nuint8 wifi_get_opmode_default(void);\r\nbool wifi_set_opmode(uint8 opmode);\r\nbool wifi_set_opmode_current(uint8 opmode);\r\nuint8 wifi_get_broadcast_if(void);\r\nbool wifi_set_broadcast_if(uint8 interface);\r\n\r\nstruct bss_info {\r\n    STAILQ_ENTRY(bss_info)     next;\r\n\r\n    uint8 bssid[6];\r\n    uint8 ssid[32];\r\n    uint8 ssid_len;\r\n    uint8 channel;\r\n    sint8 rssi;\r\n    AUTH_MODE authmode;\r\n    uint8 is_hidden;\r\n    sint16 freq_offset;\r\n    sint16 freqcal_val;\r\n    uint8 *esp_mesh_ie;\r\n};\r\n\r\ntypedef struct _scaninfo {\r\n    STAILQ_HEAD(, bss_info) *pbss;\r\n    struct espconn *pespconn;\r\n    uint8 totalpage;\r\n    uint8 pagenum;\r\n    uint8 page_sn;\r\n    uint8 data_cnt;\r\n} scaninfo;\r\n\r\ntypedef void (* scan_done_cb_t)(void *arg, STATUS status);\r\n\r\nstruct station_config {\r\n    uint8 ssid[32];\r\n    uint8 password[64];\r\n    uint8 bssid_set;    // Note: If bssid_set is 1, station will just connect to the router\r\n                        // with both ssid[] and bssid[] matched. Please check about this.\r\n    uint8 bssid[6];\r\n};\r\n\r\nbool wifi_station_get_config(struct station_config *config);\r\nbool wifi_station_get_config_default(struct station_config *config);\r\nbool wifi_station_set_config(struct station_config *config);\r\nbool wifi_station_set_config_current(struct station_config *config);\r\n\r\nbool wifi_station_connect(void);\r\nbool wifi_station_disconnect(void);\r\n\r\nsint8 wifi_station_get_rssi(void);\r\n\r\nstruct scan_config {\r\n    uint8 *ssid;    // Note: ssid == NULL, don't filter ssid.\r\n    uint8 *bssid;   // Note: bssid == NULL, don't filter bssid.\r\n    uint8 channel;  // Note: channel == 0, scan all channels, otherwise scan set channel.\r\n    uint8 show_hidden;  // Note: show_hidden == 1, can get hidden ssid routers' info.\r\n};\r\n\r\nbool wifi_station_scan(struct scan_config *config, scan_done_cb_t cb);\r\n\r\nuint8 wifi_station_get_auto_connect(void);\r\nbool wifi_station_set_auto_connect(uint8 set);\r\n\r\nbool wifi_station_set_reconnect_policy(bool set);\r\n\r\nenum {\r\n    STATION_IDLE = 0,\r\n    STATION_CONNECTING,\r\n    STATION_WRONG_PASSWORD,\r\n    STATION_NO_AP_FOUND,\r\n    STATION_CONNECT_FAIL,\r\n    STATION_GOT_IP\r\n};\r\n\r\nenum dhcp_status {\r\n    DHCP_STOPPED,\r\n    DHCP_STARTED\r\n};\r\n\r\nuint8 wifi_station_get_connect_status(void);\r\n\r\nuint8 wifi_station_get_current_ap_id(void);\r\nbool wifi_station_ap_change(uint8 current_ap_id);\r\nbool wifi_station_ap_number_set(uint8 ap_number);\r\nuint8 wifi_station_get_ap_info(struct station_config config[]);\r\n\r\nbool wifi_station_dhcpc_start(void);\r\nbool wifi_station_dhcpc_stop(void);\r\nenum dhcp_status wifi_station_dhcpc_status(void);\r\nbool wifi_station_dhcpc_set_maxtry(uint8 num);\r\n\r\nchar* wifi_station_get_hostname(void);\r\nbool wifi_station_set_hostname(char *name);\r\n\r\nstruct softap_config {\r\n    uint8 ssid[32];\r\n    uint8 password[64];\r\n    uint8 ssid_len; // Note: Recommend to set it according to your ssid\r\n    uint8 channel;  // Note: support 1 ~ 13\r\n    AUTH_MODE authmode; // Note: Don't support AUTH_WEP in softAP mode.\r\n    uint8 ssid_hidden;  // Note: default 0\r\n    uint8 max_connection;   // Note: default 4, max 4\r\n    uint16 beacon_interval; // Note: support 100 ~ 60000 ms, default 100\r\n};\r\n\r\nbool wifi_softap_get_config(struct softap_config *config);\r\nbool wifi_softap_get_config_default(struct softap_config *config);\r\nbool wifi_softap_set_config(struct softap_config *config);\r\nbool wifi_softap_set_config_current(struct softap_config *config);\r\n\r\nstruct station_info {\r\n    STAILQ_ENTRY(station_info)  next;\r\n\r\n    uint8 bssid[6];\r\n    struct ip_addr ip;\r\n};\r\n\r\nstruct dhcps_lease {\r\n    bool enable;\r\n    struct ip_addr start_ip;\r\n    struct ip_addr end_ip;\r\n};\r\n\r\nenum dhcps_offer_option{\r\n    OFFER_START = 0x00,\r\n    OFFER_ROUTER = 0x01,\r\n    OFFER_END\r\n};\r\n\r\nuint8 wifi_softap_get_station_num(void);\r\nstruct station_info * wifi_softap_get_station_info(void);\r\nvoid wifi_softap_free_station_info(void);\r\n\r\nbool wifi_softap_dhcps_start(void);\r\nbool wifi_softap_dhcps_stop(void);\r\n\r\nbool wifi_softap_set_dhcps_lease(struct dhcps_lease *please);\r\nbool wifi_softap_get_dhcps_lease(struct dhcps_lease *please);\r\nuint32 wifi_softap_get_dhcps_lease_time(void);\r\nbool wifi_softap_set_dhcps_lease_time(uint32 minute);\r\nbool wifi_softap_reset_dhcps_lease_time(void);\r\n\r\nenum dhcp_status wifi_softap_dhcps_status(void);\r\nbool wifi_softap_set_dhcps_offer_option(uint8 level, void* optarg);\r\n\r\n#define STATION_IF      0x00\r\n#define SOFTAP_IF       0x01\r\n\r\nbool wifi_get_ip_info(uint8 if_index, struct ip_info *info);\r\nbool wifi_set_ip_info(uint8 if_index, struct ip_info *info);\r\nbool wifi_get_macaddr(uint8 if_index, uint8 *macaddr);\r\nbool wifi_set_macaddr(uint8 if_index, uint8 *macaddr);\r\n\r\nuint8 wifi_get_channel(void);\r\nbool wifi_set_channel(uint8 channel);\r\n\r\nvoid wifi_status_led_install(uint8 gpio_id, uint32 gpio_name, uint8 gpio_func);\r\nvoid wifi_status_led_uninstall();\r\n\r\n/** Get the absolute difference between 2 u32_t values (correcting overflows)\r\n * 'a' is expected to be 'higher' (without overflow) than 'b'. */\r\n#define ESP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))\r\n\r\nvoid wifi_promiscuous_enable(uint8 promiscuous);\r\n\r\ntypedef void (* wifi_promiscuous_cb_t)(uint8 *buf, uint16 len);\r\n\r\nvoid wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);\r\n\r\nvoid wifi_promiscuous_set_mac(const uint8_t *address);\r\n\r\nenum phy_mode {\r\n    PHY_MODE_11B    = 1,\r\n    PHY_MODE_11G    = 2,\r\n    PHY_MODE_11N    = 3\r\n};\r\n\r\nenum phy_mode wifi_get_phy_mode(void);\r\nbool wifi_set_phy_mode(enum phy_mode mode);\r\n\r\nenum sleep_type {\r\n    NONE_SLEEP_T    = 0,\r\n    LIGHT_SLEEP_T,\r\n    MODEM_SLEEP_T\r\n};\r\n\r\nbool wifi_set_sleep_type(enum sleep_type type);\r\nenum sleep_type wifi_get_sleep_type(void);\r\n\r\nvoid wifi_fpm_open(void);\r\nvoid wifi_fpm_close(void);\r\nvoid wifi_fpm_do_wakeup(void);\r\nsint8 wifi_fpm_do_sleep(uint32 sleep_time_in_us);\r\nvoid wifi_fpm_set_sleep_type(enum sleep_type type);\r\nenum sleep_type wifi_fpm_get_sleep_type(void);\r\n\r\nenum {\r\n    EVENT_STAMODE_CONNECTED = 0,\r\n    EVENT_STAMODE_DISCONNECTED,\r\n    EVENT_STAMODE_AUTHMODE_CHANGE,\r\n    EVENT_STAMODE_GOT_IP,\r\n    EVENT_STAMODE_DHCP_TIMEOUT,\r\n    EVENT_SOFTAPMODE_STACONNECTED,\r\n    EVENT_SOFTAPMODE_STADISCONNECTED,\r\n    EVENT_SOFTAPMODE_PROBEREQRECVED,\r\n    EVENT_MAX\r\n};\r\n\r\nenum {\r\n    REASON_UNSPECIFIED              = 1,\r\n    REASON_AUTH_EXPIRE              = 2,\r\n    REASON_AUTH_LEAVE               = 3,\r\n    REASON_ASSOC_EXPIRE             = 4,\r\n    REASON_ASSOC_TOOMANY            = 5,\r\n    REASON_NOT_AUTHED               = 6,\r\n    REASON_NOT_ASSOCED              = 7,\r\n    REASON_ASSOC_LEAVE              = 8,\r\n    REASON_ASSOC_NOT_AUTHED         = 9,\r\n    REASON_DISASSOC_PWRCAP_BAD      = 10,  /* 11h */\r\n    REASON_DISASSOC_SUPCHAN_BAD     = 11,  /* 11h */\r\n    REASON_IE_INVALID               = 13,  /* 11i */\r\n    REASON_MIC_FAILURE              = 14,  /* 11i */\r\n    REASON_4WAY_HANDSHAKE_TIMEOUT   = 15,  /* 11i */\r\n    REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,  /* 11i */\r\n    REASON_IE_IN_4WAY_DIFFERS       = 17,  /* 11i */\r\n    REASON_GROUP_CIPHER_INVALID     = 18,  /* 11i */\r\n    REASON_PAIRWISE_CIPHER_INVALID  = 19,  /* 11i */\r\n    REASON_AKMP_INVALID             = 20,  /* 11i */\r\n    REASON_UNSUPP_RSN_IE_VERSION    = 21,  /* 11i */\r\n    REASON_INVALID_RSN_IE_CAP       = 22,  /* 11i */\r\n    REASON_802_1X_AUTH_FAILED       = 23,  /* 11i */\r\n    REASON_CIPHER_SUITE_REJECTED    = 24,  /* 11i */\r\n\r\n    REASON_BEACON_TIMEOUT           = 200,\r\n    REASON_NO_AP_FOUND              = 201,\r\n    REASON_AUTH_FAIL                = 202,\r\n    REASON_ASSOC_FAIL               = 203,\r\n    REASON_HANDSHAKE_TIMEOUT        = 204,\r\n};\r\n\r\ntypedef struct {\r\n    uint8 ssid[32];\r\n    uint8 ssid_len;\r\n    uint8 bssid[6];\r\n    uint8 channel;\r\n} Event_StaMode_Connected_t;\r\n\r\ntypedef struct {\r\n    uint8 ssid[32];\r\n    uint8 ssid_len;\r\n    uint8 bssid[6];\r\n    uint8 reason;\r\n} Event_StaMode_Disconnected_t;\r\n\r\ntypedef struct {\r\n    uint8 old_mode;\r\n    uint8 new_mode;\r\n} Event_StaMode_AuthMode_Change_t;\r\n\r\ntypedef struct {\r\n    struct ip_addr ip;\r\n    struct ip_addr mask;\r\n    struct ip_addr gw;\r\n} Event_StaMode_Got_IP_t;\r\n\r\ntypedef struct {\r\n    uint8 mac[6];\r\n    uint8 aid;\r\n} Event_SoftAPMode_StaConnected_t;\r\n\r\ntypedef struct {\r\n    uint8 mac[6];\r\n    uint8 aid;\r\n} Event_SoftAPMode_StaDisconnected_t;\r\n\r\ntypedef struct {\r\n    int rssi;\r\n    uint8 mac[6];\r\n} Event_SoftAPMode_ProbeReqRecved_t;\r\n\r\ntypedef union {\r\n    Event_StaMode_Connected_t           connected;\r\n    Event_StaMode_Disconnected_t        disconnected;\r\n    Event_StaMode_AuthMode_Change_t     auth_change;\r\n    Event_StaMode_Got_IP_t              got_ip;\r\n    Event_SoftAPMode_StaConnected_t     sta_connected;\r\n    Event_SoftAPMode_StaDisconnected_t  sta_disconnected;\r\n    Event_SoftAPMode_ProbeReqRecved_t   ap_probereqrecved;\r\n} Event_Info_u;\r\n\r\ntypedef struct _esp_event {\r\n    uint32 event;\r\n    Event_Info_u event_info;\r\n} System_Event_t;\r\n\r\ntypedef void (* wifi_event_handler_cb_t)(System_Event_t *event);\r\n\r\nvoid wifi_set_event_handler_cb(wifi_event_handler_cb_t cb);\r\n\r\ntypedef enum wps_type {\r\n    WPS_TYPE_DISABLE = 0,\r\n    WPS_TYPE_PBC,\r\n    WPS_TYPE_PIN,\r\n    WPS_TYPE_DISPLAY,\r\n    WPS_TYPE_MAX,\r\n} WPS_TYPE_t;\r\n\r\nenum wps_cb_status {\r\n    WPS_CB_ST_SUCCESS = 0,\r\n    WPS_CB_ST_FAILED,\r\n    WPS_CB_ST_TIMEOUT,\r\n    WPS_CB_ST_WEP,\r\n};\r\n\r\nbool wifi_wps_enable(WPS_TYPE_t wps_type);\r\nbool wifi_wps_disable(void);\r\nbool wifi_wps_start(void);\r\n\r\ntypedef void (*wps_st_cb_t)(int status);\r\nbool wifi_set_wps_cb(wps_st_cb_t cb);\r\n\r\ntypedef void (*freedom_outside_cb_t)(uint8 status);\r\nint wifi_register_send_pkt_freedom_cb(freedom_outside_cb_t cb);\r\nvoid wifi_unregister_send_pkt_freedom_cb(void);\r\nint wifi_send_pkt_freedom(uint8 *buf, int len, bool sys_seq);\r\n\r\nint wifi_rfid_locp_recv_open(void);\r\nvoid wifi_rfid_locp_recv_close(void);\r\n\r\ntypedef void (*rfid_locp_cb_t)(uint8 *frm, int len, int rssi);\r\nint wifi_register_rfid_locp_recv_cb(rfid_locp_cb_t cb);\r\nvoid wifi_unregister_rfid_locp_recv_cb(void);\r\n\r\nenum FIXED_RATE {\r\n        PHY_RATE_48       = 0x8,\r\n        PHY_RATE_24       = 0x9,\r\n        PHY_RATE_12       = 0xA,\r\n        PHY_RATE_6        = 0xB,\r\n        PHY_RATE_54       = 0xC,\r\n        PHY_RATE_36       = 0xD,\r\n        PHY_RATE_18       = 0xE,\r\n        PHY_RATE_9        = 0xF,\r\n};\r\n\r\n#define FIXED_RATE_MASK_NONE    0x00\r\n#define FIXED_RATE_MASK_STA     0x01\r\n#define FIXED_RATE_MASK_AP      0x02\r\n#define FIXED_RATE_MASK_ALL     0x03\r\n\r\nint wifi_set_user_fixed_rate(uint8 enable_mask, uint8 rate);\r\nint wifi_get_user_fixed_rate(uint8 *enable_mask, uint8 *rate);\r\n\r\nenum support_rate {\r\n    RATE_11B5M  = 0,\r\n    RATE_11B11M = 1,\r\n    RATE_11B1M  = 2,\r\n    RATE_11B2M  = 3,\r\n    RATE_11G6M  = 4,\r\n    RATE_11G12M = 5,\r\n    RATE_11G24M = 6,\r\n    RATE_11G48M = 7,\r\n    RATE_11G54M = 8,\r\n    RATE_11G9M  = 9,\r\n    RATE_11G18M = 10,\r\n    RATE_11G36M = 11,\r\n};\r\n\r\nint wifi_set_user_sup_rate(uint8 min, uint8 max);\r\n\r\nenum RATE_11B_ID {\r\n    RATE_11B_B11M   = 0,\r\n    RATE_11B_B5M    = 1,\r\n    RATE_11B_B2M    = 2,\r\n    RATE_11B_B1M    = 3,\r\n};\r\n\r\nenum RATE_11G_ID {\r\n    RATE_11G_G54M   = 0,\r\n    RATE_11G_G48M   = 1,\r\n    RATE_11G_G36M   = 2,\r\n    RATE_11G_G24M   = 3,\r\n    RATE_11G_G18M   = 4,\r\n    RATE_11G_G12M   = 5,\r\n    RATE_11G_G9M    = 6,\r\n    RATE_11G_G6M    = 7,\r\n    RATE_11G_B5M    = 8,\r\n    RATE_11G_B2M    = 9,\r\n    RATE_11G_B1M    = 10\r\n};\r\n\r\nenum RATE_11N_ID {\r\n    RATE_11N_MCS7S  = 0,\r\n    RATE_11N_MCS7   = 1,\r\n    RATE_11N_MCS6   = 2,\r\n    RATE_11N_MCS5   = 3,\r\n    RATE_11N_MCS4   = 4,\r\n    RATE_11N_MCS3   = 5,\r\n    RATE_11N_MCS2   = 6,\r\n    RATE_11N_MCS1   = 7,\r\n    RATE_11N_MCS0   = 8,\r\n    RATE_11N_B5M    = 9,\r\n    RATE_11N_B2M    = 10,\r\n    RATE_11N_B1M    = 11\r\n};\r\n\r\n#define RC_LIMIT_11B        0\r\n#define RC_LIMIT_11G        1\r\n#define RC_LIMIT_11N        2\r\n#define RC_LIMIT_P2P_11G    3\r\n#define RC_LIMIT_P2P_11N    4\r\n#define RC_LIMIT_NUM        5\r\n\r\n#define LIMIT_RATE_MASK_NONE    0x00\r\n#define LIMIT_RATE_MASK_STA     0x01\r\n#define LIMIT_RATE_MASK_AP      0x02\r\n#define LIMIT_RATE_MASK_ALL     0x03\r\n\r\nbool wifi_set_user_rate_limit(uint8 mode, uint8 ifidx, uint8 max, uint8 min);\r\nuint8 wifi_get_user_limit_rate_mask(void);\r\nbool wifi_set_user_limit_rate_mask(uint8 enable_mask);\r\n\r\nenum {\r\n    USER_IE_BEACON = 0,\r\n    USER_IE_PROBE_REQ,\r\n    USER_IE_PROBE_RESP,\r\n    USER_IE_ASSOC_REQ,\r\n    USER_IE_ASSOC_RESP,\r\n    USER_IE_MAX\r\n};\r\n\r\ntypedef void (*user_ie_manufacturer_recv_cb_t)(uint8 type, const uint8 sa[6], const uint8 m_oui[3], uint8 *ie, uint8 ie_len, int rssi);\r\n\r\nbool wifi_set_user_ie(bool enable, uint8 *m_oui, uint8 type, uint8 *user_ie, uint8 len);\r\nint wifi_register_user_ie_manufacturer_recv_cb(user_ie_manufacturer_recv_cb_t cb);\r\nvoid wifi_unregister_user_ie_manufacturer_recv_cb(void);\r\n\r\n#endif\r\n"
  },
  {
    "path": "ld/eagle.app.v6.ld",
    "content": "/* This linker script generated from xt-genldscripts.tpp for LSP . */\n/* Linker Script for ld -N */\nMEMORY\n{\n  dport0_0_seg :                      \torg = 0x3FF00000, len = 0x10\n  dram0_0_seg :                       \torg = 0x3FFE8000, len = 0x14000\n  iram1_0_seg :                       \torg = 0x40100000, len = 0x8000\n  irom0_0_seg :                       \torg = 0x40210000, len = 0x51000\n}\n\nPHDRS\n{\n  dport0_0_phdr PT_LOAD;\n  dram0_0_phdr PT_LOAD;\n  dram0_0_bss_phdr PT_LOAD;\n  iram1_0_phdr PT_LOAD;\n  irom0_0_phdr PT_LOAD;\n}\n\n\n/*  Default entry point:  */\nENTRY(call_user_start)\nEXTERN(_DebugExceptionVector)\nEXTERN(_DoubleExceptionVector)\nEXTERN(_KernelExceptionVector)\nEXTERN(_NMIExceptionVector)\nEXTERN(_UserExceptionVector)\nPROVIDE(_memmap_vecbase_reset = 0x40000000);\n/* Various memory-map dependent cache attribute settings: */\n_memmap_cacheattr_wb_base = 0x00000110;\n_memmap_cacheattr_wt_base = 0x00000110;\n_memmap_cacheattr_bp_base = 0x00000220;\n_memmap_cacheattr_unused_mask = 0xFFFFF00F;\n_memmap_cacheattr_wb_trapnull = 0x2222211F;\n_memmap_cacheattr_wba_trapnull = 0x2222211F;\n_memmap_cacheattr_wbna_trapnull = 0x2222211F;\n_memmap_cacheattr_wt_trapnull = 0x2222211F;\n_memmap_cacheattr_bp_trapnull = 0x2222222F;\n_memmap_cacheattr_wb_strict = 0xFFFFF11F;\n_memmap_cacheattr_wt_strict = 0xFFFFF11F;\n_memmap_cacheattr_bp_strict = 0xFFFFF22F;\n_memmap_cacheattr_wb_allvalid = 0x22222112;\n_memmap_cacheattr_wt_allvalid = 0x22222112;\n_memmap_cacheattr_bp_allvalid = 0x22222222;\nPROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull);\n\nSECTIONS\n{\n\n  .dport0.rodata : ALIGN(4)\n  {\n    _dport0_rodata_start = ABSOLUTE(.);\n    *(.dport0.rodata)\n    *(.dport.rodata)\n    _dport0_rodata_end = ABSOLUTE(.);\n  } >dport0_0_seg :dport0_0_phdr\n\n  .dport0.literal : ALIGN(4)\n  {\n    _dport0_literal_start = ABSOLUTE(.);\n    *(.dport0.literal)\n    *(.dport.literal)\n    _dport0_literal_end = ABSOLUTE(.);\n  } >dport0_0_seg :dport0_0_phdr\n\n  .dport0.data : ALIGN(4)\n  {\n    _dport0_data_start = ABSOLUTE(.);\n    *(.dport0.data)\n    *(.dport.data)\n    _dport0_data_end = ABSOLUTE(.);\n  } >dport0_0_seg :dport0_0_phdr\n\n\n  .lit4 : ALIGN(4)\n  {\n    _lit4_start = ABSOLUTE(.);\n    *(*.lit4)\n    *(.lit4.*)\n    *(.gnu.linkonce.lit4.*)\n    _lit4_end = ABSOLUTE(.);\n  } >iram1_0_seg :iram1_0_phdr\n  \n  \n  .irom0.text : ALIGN(4)\n  {\n    _irom0_text_start = ABSOLUTE(.);\n    *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text)\n    *(.literal.* .text.*)\n    *(.rodata2.text)\n    _irom0_text_end = ABSOLUTE(.);\n    _flash_used_end = ABSOLUTE(.);\n  } >irom0_0_seg :irom0_0_phdr\n  \n  .text : ALIGN(4)\n  {\n    _stext = .;\n    _text_start = ABSOLUTE(.);\n    *(.UserEnter.text)\n    . = ALIGN(16);\n    *(.DebugExceptionVector.text)\n    . = ALIGN(16);\n    *(.NMIExceptionVector.text)\n    . = ALIGN(16);\n    *(.KernelExceptionVector.text)\n    LONG(0)\n    LONG(0)\n    LONG(0)\n    LONG(0)\n    . = ALIGN(16);\n    *(.UserExceptionVector.text)\n    LONG(0)\n    LONG(0)\n    LONG(0)\n    LONG(0)\n    . = ALIGN(16);\n    *(.DoubleExceptionVector.text)\n    LONG(0)\n    LONG(0)\n    LONG(0)\n    LONG(0)\n    . = ALIGN (16);\n    *(.entry.text)\n    *(.init.literal)\n    *(.init)\n    *(.literal .text .iram0.text .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)\n    *(.fini.literal)\n    *(.fini)\n    *(.gnu.version)\n    _text_end = ABSOLUTE(.);\n    _etext = .;\n\n  } >iram1_0_seg :iram1_0_phdr\n\n  .lit4 : ALIGN(4)\n  {\n    _lit4_start = ABSOLUTE(.);\n    *(*.lit4)\n    *(.lit4.*)\n    *(.gnu.linkonce.lit4.*)\n    _lit4_end = ABSOLUTE(.);\n  } >iram1_0_seg :iram1_0_phdr\n\n  .data : ALIGN(4)\n  {\n    _data_start = ABSOLUTE(.);\n    *(.data)\n    *(.data.*)\n    *(.gnu.linkonce.d.*)\n    *(.data1)\n    *(.sdata)\n    *(.sdata.*)\n    *(.gnu.linkonce.s.*)\n    *(.sdata2)\n    *(.sdata2.*)\n    *(.gnu.linkonce.s2.*)\n    *(.jcr)\n    _data_end = ABSOLUTE(.);\n  } >dram0_0_seg :dram0_0_phdr\n\n  .rodata : ALIGN(4)\n  {\n    _rodata_start = ABSOLUTE(.);\n\t*(.sdk.version)\n    *(.rodata)\n    *(.rodata.*)\n    *(.gnu.linkonce.r.*)\n    *(.rodata1)\n    __XT_EXCEPTION_TABLE__ = ABSOLUTE(.);\n    *(.xt_except_table)\n    *(.gcc_except_table)\n    *(.gnu.linkonce.e.*)\n    *(.gnu.version_r)\n    *(.eh_frame)\n    /*  C++ constructor and destructor tables, properly ordered:  */\n    KEEP (*crtbegin.o(.ctors))\n    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))\n    KEEP (*(SORT(.ctors.*)))\n    KEEP (*(.ctors))\n    KEEP (*crtbegin.o(.dtors))\n    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))\n    KEEP (*(SORT(.dtors.*)))\n    KEEP (*(.dtors))\n    /*  C++ exception handlers table:  */\n    __XT_EXCEPTION_DESCS__ = ABSOLUTE(.);\n    *(.xt_except_desc)\n    *(.gnu.linkonce.h.*)\n    __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.);\n    *(.xt_except_desc_end)\n    *(.dynamic)\n    *(.gnu.version_d)\n    . = ALIGN(4);\t\t/* this table MUST be 4-byte aligned */\n    _bss_table_start = ABSOLUTE(.);\n    LONG(_bss_start)\n    LONG(_bss_end)\n    _bss_table_end = ABSOLUTE(.);\n    _rodata_end = ABSOLUTE(.);\n  } >dram0_0_seg :dram0_0_phdr\n\n  .bss ALIGN(8) (NOLOAD) : ALIGN(4)\n  {\n    . = ALIGN (8);\n    _bss_start = ABSOLUTE(.);\n    *(.dynsbss)\n    *(.sbss)\n    *(.sbss.*)\n    *(.gnu.linkonce.sb.*)\n    *(.scommon)\n    *(.sbss2)\n    *(.sbss2.*)\n    *(.gnu.linkonce.sb2.*)\n    *(.dynbss)\n    *(.bss)\n    *(.bss.*)\n    *(.gnu.linkonce.b.*)\n    *(COMMON)\n    . = ALIGN (8);\n    _bss_end = ABSOLUTE(.);\n    _heap_start = ABSOLUTE(.);\n/*    _stack_sentry = ALIGN(0x8); */\n  } >dram0_0_seg :dram0_0_bss_phdr\n/* __stack = 0x3ffc8000; */\n\n}\n\n/* get ROM code address */\nINCLUDE \"../ld/eagle.rom.addr.v6.ld\"\n"
  },
  {
    "path": "ld/eagle.rom.addr.v6.ld",
    "content": "PROVIDE ( Cache_Read_Disable = 0x400047f0 );\nPROVIDE ( Cache_Read_Enable = 0x40004678 );\nPROVIDE ( FilePacketSendReqMsgProc = 0x400035a0 );\nPROVIDE ( FlashDwnLdParamCfgMsgProc = 0x4000368c );\nPROVIDE ( FlashDwnLdStartMsgProc = 0x40003538 );\nPROVIDE ( FlashDwnLdStopReqMsgProc = 0x40003658 );\nPROVIDE ( GetUartDevice = 0x40003f4c );\nPROVIDE ( MD5Final = 0x40009900 );\nPROVIDE ( MD5Init = 0x40009818 );\nPROVIDE ( MD5Update = 0x40009834 );\nPROVIDE ( MemDwnLdStartMsgProc = 0x400036c4 );\nPROVIDE ( MemDwnLdStopReqMsgProc = 0x4000377c );\nPROVIDE ( MemPacketSendReqMsgProc = 0x400036f0 );\nPROVIDE ( RcvMsg = 0x40003eac );\nPROVIDE ( SHA1Final = 0x4000b648 );\nPROVIDE ( SHA1Init = 0x4000b584 );\nPROVIDE ( SHA1Transform = 0x4000a364 );\nPROVIDE ( SHA1Update = 0x4000b5a8 );\nPROVIDE ( SPI_read_status = 0x400043c8 );\nPROVIDE ( SPI_write_status = 0x40004400 );\nPROVIDE ( SPI_write_enable = 0x4000443c );\nPROVIDE ( Wait_SPI_Idle = 0x4000448c );\nPROVIDE ( SPIEraseArea = 0x40004b44 );\nPROVIDE ( SPIEraseBlock = 0x400049b4 );\nPROVIDE ( SPIEraseChip = 0x40004984 );\nPROVIDE ( SPIEraseSector = 0x40004a00 );\nPROVIDE ( SPILock = 0x400048a8 );\nPROVIDE ( SPIParamCfg = 0x40004c2c );\nPROVIDE ( SPIRead = 0x40004b1c );\nPROVIDE ( SPIReadModeCnfig = 0x400048ec );\nPROVIDE ( SPIUnlock = 0x40004878 );\nPROVIDE ( SPIWrite = 0x40004a4c );\nPROVIDE ( SelectSpiFunction = 0x40003f58 );\nPROVIDE ( SendMsg = 0x40003cf4 );\nPROVIDE ( UartConnCheck = 0x40003230 );\nPROVIDE ( UartConnectProc = 0x400037a0 );\nPROVIDE ( UartDwnLdProc = 0x40003368 );\nPROVIDE ( UartGetCmdLn = 0x40003ef4 );\nPROVIDE ( UartRegReadProc = 0x4000381c );\nPROVIDE ( UartRegWriteProc = 0x400037ac );\nPROVIDE ( UartRxString = 0x40003c30 );\nPROVIDE ( Uart_Init = 0x40003a14 );\nPROVIDE ( _DebugExceptionVector = 0x40000010 );\nPROVIDE ( _DoubleExceptionVector = 0x40000070 );\nPROVIDE ( _KernelExceptionVector = 0x40000030 );\nPROVIDE ( _NMIExceptionVector = 0x40000020 );\nPROVIDE ( _ResetHandler = 0x400000a4 );\nPROVIDE ( _ResetVector = 0x40000080 );\nPROVIDE ( _UserExceptionVector = 0x40000050 );\nPROVIDE ( __adddf3 = 0x4000c538 );\nPROVIDE ( __addsf3 = 0x4000c180 );\nPROVIDE ( __divdf3 = 0x4000cb94 );\nPROVIDE ( __divdi3 = 0x4000ce60 );\nPROVIDE ( __divsi3 = 0x4000dc88 );\nPROVIDE ( __extendsfdf2 = 0x4000cdfc );\nPROVIDE ( __fixdfsi = 0x4000ccb8 );\nPROVIDE ( __fixunsdfsi = 0x4000cd00 );\nPROVIDE ( __fixunssfsi = 0x4000c4c4 );\nPROVIDE ( __floatsidf = 0x4000e2f0 );\nPROVIDE ( __floatsisf = 0x4000e2ac );\nPROVIDE ( __floatunsidf = 0x4000e2e8 );\nPROVIDE ( __floatunsisf = 0x4000e2a4 );\nPROVIDE ( __muldf3 = 0x4000c8f0 );\nPROVIDE ( __muldi3 = 0x40000650 );\nPROVIDE ( __mulsf3 = 0x4000c3dc );\nPROVIDE ( __subdf3 = 0x4000c688 );\nPROVIDE ( __subsf3 = 0x4000c268 );\nPROVIDE ( __truncdfsf2 = 0x4000cd5c );\nPROVIDE ( __udivdi3 = 0x4000d310 );\nPROVIDE ( __udivsi3 = 0x4000e21c );\nPROVIDE ( __umoddi3 = 0x4000d770 );\nPROVIDE ( __umodsi3 = 0x4000e268 );\nPROVIDE ( __umulsidi3 = 0x4000dcf0 );\nPROVIDE ( _rom_store = 0x4000e388 );\nPROVIDE ( _rom_store_table = 0x4000e328 );\nPROVIDE ( _start = 0x4000042c );\nPROVIDE ( _xtos_alloca_handler = 0x4000dbe0 );\nPROVIDE ( _xtos_c_wrapper_handler = 0x40000598 );\nPROVIDE ( _xtos_cause3_handler = 0x40000590 );\nPROVIDE ( _xtos_ints_off = 0x4000bda4 );\nPROVIDE ( _xtos_ints_on = 0x4000bd84 );\nPROVIDE ( _xtos_l1int_handler = 0x4000048c );\nPROVIDE ( _xtos_p_none = 0x4000dbf8 );\nPROVIDE ( _xtos_restore_intlevel = 0x4000056c );\nPROVIDE ( _xtos_return_from_exc = 0x4000dc54 );\nPROVIDE ( _xtos_set_exception_handler = 0x40000454 );\nPROVIDE ( _xtos_set_interrupt_handler = 0x4000bd70 );\nPROVIDE ( _xtos_set_interrupt_handler_arg = 0x4000bd28 );\nPROVIDE ( _xtos_set_intlevel = 0x4000dbfc );\nPROVIDE ( _xtos_set_min_intlevel = 0x4000dc18 );\nPROVIDE ( _xtos_set_vpri = 0x40000574 );\nPROVIDE ( _xtos_syscall_handler = 0x4000dbe4 );\nPROVIDE ( _xtos_unhandled_exception = 0x4000dc44 );\nPROVIDE ( _xtos_unhandled_interrupt = 0x4000dc3c );\nPROVIDE ( aes_decrypt = 0x400092d4 );\nPROVIDE ( aes_decrypt_deinit = 0x400092e4 );\nPROVIDE ( aes_decrypt_init = 0x40008ea4 );\nPROVIDE ( aes_unwrap = 0x40009410 );\nPROVIDE ( base64_decode = 0x40009648 );\nPROVIDE ( base64_encode = 0x400094fc );\nPROVIDE ( bzero = 0x4000de84 );\nPROVIDE ( cmd_parse = 0x40000814 );\nPROVIDE ( conv_str_decimal = 0x40000b24 );\nPROVIDE ( conv_str_hex = 0x40000cb8 );\nPROVIDE ( convert_para_str = 0x40000a60 );\nPROVIDE ( dtm_get_intr_mask = 0x400026d0 );\nPROVIDE ( dtm_params_init = 0x4000269c );\nPROVIDE ( dtm_set_intr_mask = 0x400026c8 );\nPROVIDE ( dtm_set_params = 0x400026dc );\nPROVIDE ( eprintf = 0x40001d14 );\nPROVIDE ( eprintf_init_buf = 0x40001cb8 );\nPROVIDE ( eprintf_to_host = 0x40001d48 );\nPROVIDE ( est_get_printf_buf_remain_len = 0x40002494 );\nPROVIDE ( est_reset_printf_buf_len = 0x4000249c );\nPROVIDE ( ets_bzero = 0x40002ae8 );\nPROVIDE ( ets_char2xdigit = 0x40002b74 );\nPROVIDE ( ets_delay_us = 0x40002ecc );\nPROVIDE ( ets_enter_sleep = 0x400027b8 );\nPROVIDE ( ets_external_printf = 0x40002578 );\nPROVIDE ( ets_get_cpu_frequency = 0x40002f0c );\nPROVIDE ( ets_getc = 0x40002bcc );\nPROVIDE ( ets_install_external_printf = 0x40002450 );\nPROVIDE ( ets_install_putc1 = 0x4000242c );\nPROVIDE ( ets_install_putc2 = 0x4000248c );\nPROVIDE ( ets_install_uart_printf = 0x40002438 );\nPROVIDE ( ets_intr_lock = 0x40000f74 );\nPROVIDE ( ets_intr_unlock = 0x40000f80 );\nPROVIDE ( ets_isr_attach = 0x40000f88 );\nPROVIDE ( ets_isr_mask = 0x40000f98 );\nPROVIDE ( ets_isr_unmask = 0x40000fa8 );\nPROVIDE ( ets_memcmp = 0x400018d4 );\nPROVIDE ( ets_memcpy = 0x400018b4 );\nPROVIDE ( ets_memmove = 0x400018c4 );\nPROVIDE ( ets_memset = 0x400018a4 );\nPROVIDE ( ets_post = 0x40000e24 );\nPROVIDE ( ets_printf = 0x400024cc );\nPROVIDE ( ets_putc = 0x40002be8 );\nPROVIDE ( ets_rtc_int_register = 0x40002a40 );\nPROVIDE ( ets_run = 0x40000e04 );\nPROVIDE ( ets_set_idle_cb = 0x40000dc0 );\nPROVIDE ( ets_set_user_start = 0x40000fbc );\nPROVIDE ( ets_str2macaddr = 0x40002af8 );\nPROVIDE ( ets_strcmp = 0x40002aa8 );\nPROVIDE ( ets_strcpy = 0x40002a88 );\nPROVIDE ( ets_strlen = 0x40002ac8 );\nPROVIDE ( ets_strncmp = 0x40002ab8 );\nPROVIDE ( ets_strncpy = 0x40002a98 );\nPROVIDE ( ets_strstr = 0x40002ad8 );\nPROVIDE ( ets_task = 0x40000dd0 );\nPROVIDE ( ets_timer_arm = 0x40002cc4 );\nPROVIDE ( ets_timer_disarm = 0x40002d40 );\nPROVIDE ( ets_timer_done = 0x40002d80 );\nPROVIDE ( ets_timer_handler_isr = 0x40002da8 );\nPROVIDE ( ets_timer_init = 0x40002e68 );\nPROVIDE ( ets_timer_setfn = 0x40002c48 );\nPROVIDE ( ets_uart_printf = 0x40002544 );\nPROVIDE ( ets_update_cpu_frequency = 0x40002f04 );\nPROVIDE ( ets_vprintf = 0x40001f00 );\nPROVIDE ( ets_wdt_disable = 0x400030f0 );\nPROVIDE ( ets_wdt_enable = 0x40002fa0 );\nPROVIDE ( ets_wdt_get_mode = 0x40002f34 );\nPROVIDE ( ets_wdt_init = 0x40003170 );\nPROVIDE ( ets_wdt_restore = 0x40003158 );\nPROVIDE ( ets_write_char = 0x40001da0 );\nPROVIDE ( get_first_seg = 0x4000091c );\nPROVIDE ( gpio_init = 0x40004c50 );\nPROVIDE ( gpio_input_get = 0x40004cf0 );\nPROVIDE ( gpio_intr_ack = 0x40004dcc );\nPROVIDE ( gpio_intr_handler_register = 0x40004e28 );\nPROVIDE ( gpio_intr_pending = 0x40004d88 );\nPROVIDE ( gpio_intr_test = 0x40004efc );\nPROVIDE ( gpio_output_set = 0x40004cd0 );\nPROVIDE ( gpio_pin_intr_state_set = 0x40004d90 );\nPROVIDE ( gpio_pin_wakeup_disable = 0x40004ed4 );\nPROVIDE ( gpio_pin_wakeup_enable = 0x40004e90 );\nPROVIDE ( gpio_register_get = 0x40004d5c );\nPROVIDE ( gpio_register_set = 0x40004d04 );\nPROVIDE ( hmac_md5 = 0x4000a2cc );\nPROVIDE ( hmac_md5_vector = 0x4000a160 );\nPROVIDE ( hmac_sha1 = 0x4000ba28 );\nPROVIDE ( hmac_sha1_vector = 0x4000b8b4 );\nPROVIDE ( lldesc_build_chain = 0x40004f40 );\nPROVIDE ( lldesc_num2link = 0x40005050 );\nPROVIDE ( lldesc_set_owner = 0x4000507c );\nPROVIDE ( main = 0x40000fec );\nPROVIDE ( md5_vector = 0x400097ac );\nPROVIDE ( mem_calloc = 0x40001c2c );\nPROVIDE ( mem_free = 0x400019e0 );\nPROVIDE ( mem_init = 0x40001998 );\nPROVIDE ( mem_malloc = 0x40001b40 );\nPROVIDE ( mem_realloc = 0x40001c6c );\nPROVIDE ( mem_trim = 0x40001a14 );\nPROVIDE ( mem_zalloc = 0x40001c58 );\nPROVIDE ( memcmp = 0x4000dea8 );\nPROVIDE ( memcpy = 0x4000df48 );\nPROVIDE ( memmove = 0x4000e04c );\nPROVIDE ( memset = 0x4000e190 );\nPROVIDE ( multofup = 0x400031c0 );\nPROVIDE ( pbkdf2_sha1 = 0x4000b840 );\nPROVIDE ( phy_get_romfuncs = 0x40006b08 );\nPROVIDE ( rand = 0x40000600 );\nPROVIDE ( rc4_skip = 0x4000dd68 );\nPROVIDE ( recv_packet = 0x40003d08 );\nPROVIDE ( remove_head_space = 0x40000a04 );\nPROVIDE ( rijndaelKeySetupDec = 0x40008dd0 );\nPROVIDE ( rijndaelKeySetupEnc = 0x40009300 );\nPROVIDE ( rom_abs_temp = 0x400060c0 );\nPROVIDE ( rom_ana_inf_gating_en = 0x40006b10 );\nPROVIDE ( rom_cal_tos_v50 = 0x40007a28 );\nPROVIDE ( rom_chip_50_set_channel = 0x40006f84 );\nPROVIDE ( rom_chip_v5_disable_cca = 0x400060d0 );\nPROVIDE ( rom_chip_v5_enable_cca = 0x400060ec );\nPROVIDE ( rom_chip_v5_rx_init = 0x4000711c );\nPROVIDE ( rom_chip_v5_sense_backoff = 0x4000610c );\nPROVIDE ( rom_chip_v5_tx_init = 0x4000718c );\nPROVIDE ( rom_dc_iq_est = 0x4000615c );\nPROVIDE ( rom_en_pwdet = 0x400061b8 );\nPROVIDE ( rom_get_bb_atten = 0x40006238 );\nPROVIDE ( rom_get_corr_power = 0x40006260 );\nPROVIDE ( rom_get_fm_sar_dout = 0x400062dc );\nPROVIDE ( rom_get_noisefloor = 0x40006394 );\nPROVIDE ( rom_get_power_db = 0x400063b0 );\nPROVIDE ( rom_i2c_readReg = 0x40007268 );\nPROVIDE ( rom_i2c_readReg_Mask = 0x4000729c );\nPROVIDE ( rom_i2c_writeReg = 0x400072d8 );\nPROVIDE ( rom_i2c_writeReg_Mask = 0x4000730c );\nPROVIDE ( rom_iq_est_disable = 0x40006400 );\nPROVIDE ( rom_iq_est_enable = 0x40006430 );\nPROVIDE ( rom_linear_to_db = 0x40006484 );\nPROVIDE ( rom_mhz2ieee = 0x400065a4 );\nPROVIDE ( rom_pbus_dco___SA2 = 0x40007bf0 );\nPROVIDE ( rom_pbus_debugmode = 0x4000737c );\nPROVIDE ( rom_pbus_enter_debugmode = 0x40007410 );\nPROVIDE ( rom_pbus_exit_debugmode = 0x40007448 );\nPROVIDE ( rom_pbus_force_test = 0x4000747c );\nPROVIDE ( rom_pbus_rd = 0x400074d8 );\nPROVIDE ( rom_pbus_set_rxgain = 0x4000754c );\nPROVIDE ( rom_pbus_set_txgain = 0x40007610 );\nPROVIDE ( rom_pbus_workmode = 0x40007648 );\nPROVIDE ( rom_pbus_xpd_rx_off = 0x40007688 );\nPROVIDE ( rom_pbus_xpd_rx_on = 0x400076cc );\nPROVIDE ( rom_pbus_xpd_tx_off = 0x400076fc );\nPROVIDE ( rom_pbus_xpd_tx_on = 0x40007740 );\nPROVIDE ( rom_pbus_xpd_tx_on__low_gain = 0x400077a0 );\nPROVIDE ( rom_phy_reset_req = 0x40007804 );\nPROVIDE ( rom_restart_cal = 0x4000781c );\nPROVIDE ( rom_rfcal_pwrctrl = 0x40007eb4 );\nPROVIDE ( rom_rfcal_rxiq = 0x4000804c );\nPROVIDE ( rom_rfcal_rxiq_set_reg = 0x40008264 );\nPROVIDE ( rom_rfcal_txcap = 0x40008388 );\nPROVIDE ( rom_rfcal_txiq = 0x40008610 );\nPROVIDE ( rom_rfcal_txiq_cover = 0x400088b8 );\nPROVIDE ( rom_rfcal_txiq_set_reg = 0x40008a70 );\nPROVIDE ( rom_rfpll_reset = 0x40007868 );\nPROVIDE ( rom_rfpll_set_freq = 0x40007968 );\nPROVIDE ( rom_rxiq_cover_mg_mp = 0x40008b6c );\nPROVIDE ( rom_rxiq_get_mis = 0x40006628 );\nPROVIDE ( rom_sar_init = 0x40006738 );\nPROVIDE ( rom_set_ana_inf_tx_scale = 0x4000678c );\nPROVIDE ( rom_set_channel_freq = 0x40006c50 );\nPROVIDE ( rom_set_loopback_gain = 0x400067c8 );\nPROVIDE ( rom_set_noise_floor = 0x40006830 );\nPROVIDE ( rom_set_rxclk_en = 0x40006550 );\nPROVIDE ( rom_set_txbb_atten = 0x40008c6c );\nPROVIDE ( rom_set_txclk_en = 0x4000650c );\nPROVIDE ( rom_set_txiq_cal = 0x40008d34 );\nPROVIDE ( rom_start_noisefloor = 0x40006874 );\nPROVIDE ( rom_start_tx_tone = 0x400068b4 );\nPROVIDE ( rom_stop_tx_tone = 0x4000698c );\nPROVIDE ( rom_tx_mac_disable = 0x40006a98 );\nPROVIDE ( rom_tx_mac_enable = 0x40006ad4 );\nPROVIDE ( rom_txtone_linear_pwr = 0x40006a1c );\nPROVIDE ( rom_write_rfpll_sdm = 0x400078dc );\nPROVIDE ( roundup2 = 0x400031b4 );\nPROVIDE ( rtc_enter_sleep = 0x40002870 );\nPROVIDE ( rtc_get_reset_reason = 0x400025e0 );\nPROVIDE ( rtc_intr_handler = 0x400029ec );\nPROVIDE ( rtc_set_sleep_mode = 0x40002668 );\nPROVIDE ( save_rxbcn_mactime = 0x400027a4 );\nPROVIDE ( save_tsf_us = 0x400027ac );\nPROVIDE ( send_packet = 0x40003c80 );\nPROVIDE ( sha1_prf = 0x4000ba48 );\nPROVIDE ( sha1_vector = 0x4000a2ec );\nPROVIDE ( sip_alloc_to_host_evt = 0x40005180 );\nPROVIDE ( sip_get_ptr = 0x400058a8 );\nPROVIDE ( sip_get_state = 0x40005668 );\nPROVIDE ( sip_init_attach = 0x4000567c );\nPROVIDE ( sip_install_rx_ctrl_cb = 0x4000544c );\nPROVIDE ( sip_install_rx_data_cb = 0x4000545c );\nPROVIDE ( sip_post = 0x400050fc );\nPROVIDE ( sip_post_init = 0x400056c4 );\nPROVIDE ( sip_reclaim_from_host_cmd = 0x4000534c );\nPROVIDE ( sip_reclaim_tx_data_pkt = 0x400052c0 );\nPROVIDE ( sip_send = 0x40005808 );\nPROVIDE ( sip_to_host_chain_append = 0x40005864 );\nPROVIDE ( sip_to_host_evt_send_done = 0x40005234 );\nPROVIDE ( slc_add_credits = 0x400060ac );\nPROVIDE ( slc_enable = 0x40005d90 );\nPROVIDE ( slc_from_host_chain_fetch = 0x40005f24 );\nPROVIDE ( slc_from_host_chain_recycle = 0x40005e94 );\nPROVIDE ( slc_init_attach = 0x40005c50 );\nPROVIDE ( slc_init_credit = 0x4000608c );\nPROVIDE ( slc_pause_from_host = 0x40006014 );\nPROVIDE ( slc_reattach = 0x40005c1c );\nPROVIDE ( slc_resume_from_host = 0x4000603c );\nPROVIDE ( slc_select_tohost_gpio = 0x40005dc0 );\nPROVIDE ( slc_select_tohost_gpio_mode = 0x40005db8 );\nPROVIDE ( slc_send_to_host_chain = 0x40005de4 );\nPROVIDE ( slc_set_host_io_max_window = 0x40006068 );\nPROVIDE ( slc_to_host_chain_recycle = 0x40005f10 );\nPROVIDE ( software_reset = 0x4000264c );\nPROVIDE ( spi_flash_attach = 0x40004644 );\nPROVIDE ( srand = 0x400005f0 );\nPROVIDE ( strcmp = 0x4000bdc8 );\nPROVIDE ( strcpy = 0x4000bec8 );\nPROVIDE ( strlen = 0x4000bf4c );\nPROVIDE ( strncmp = 0x4000bfa8 );\nPROVIDE ( strncpy = 0x4000c0a0 );\nPROVIDE ( strstr = 0x4000e1e0 );\nPROVIDE ( timer_insert = 0x40002c64 );\nPROVIDE ( uartAttach = 0x4000383c );\nPROVIDE ( uart_baudrate_detect = 0x40003924 );\nPROVIDE ( uart_buff_switch = 0x400038a4 );\nPROVIDE ( uart_div_modify = 0x400039d8 );\nPROVIDE ( uart_rx_intr_handler = 0x40003bbc );\nPROVIDE ( uart_rx_one_char = 0x40003b8c );\nPROVIDE ( uart_rx_one_char_block = 0x40003b64 );\nPROVIDE ( uart_rx_readbuff = 0x40003ec8 );\nPROVIDE ( uart_tx_one_char = 0x40003b30 );\nPROVIDE ( wepkey_128 = 0x4000bc40 );\nPROVIDE ( wepkey_64 = 0x4000bb3c );\nPROVIDE ( xthal_bcopy = 0x40000688 );\nPROVIDE ( xthal_copy123 = 0x4000074c );\nPROVIDE ( xthal_get_ccompare = 0x4000dd4c );\nPROVIDE ( xthal_get_ccount = 0x4000dd38 );\nPROVIDE ( xthal_get_interrupt = 0x4000dd58 );\nPROVIDE ( xthal_get_intread = 0x4000dd58 );\nPROVIDE ( xthal_memcpy = 0x400006c4 );\nPROVIDE ( xthal_set_ccompare = 0x4000dd40 );\nPROVIDE ( xthal_set_intclear = 0x4000dd60 );\nPROVIDE ( xthal_spill_registers_into_stack_nw = 0x4000e320 );\nPROVIDE ( xthal_window_spill = 0x4000e324 );\nPROVIDE ( xthal_window_spill_nw = 0x4000e320 );\n\nPROVIDE ( Te0 = 0x3fffccf0 );\nPROVIDE ( UartDev = 0x3fffde10 );\nPROVIDE ( flashchip = 0x3fffc714);\n"
  },
  {
    "path": "tools/.gitattributes",
    "content": "# Enforce Unix newlines\n*.css   text eol=lf\n*.html  text eol=lf\n*.js    text eol=lf\n*.json  text eol=lf\n*.less  text eol=lf\n*.md    text eol=lf\n*.svg   text eol=lf\n*.yml   text eol=lf\n*.py\ttext eol=lf\n*.sh\ttext eol=lf\n"
  },
  {
    "path": "tools/esptool.py",
    "content": "#!/usr/bin/env python2\n#\n# ESP8266 ROM Bootloader Utility\n# https://github.com/themadinventor/esptool\n#\n# Copyright (C) 2014 Fredrik Ahlberg\n#\n# This program is free software; you can redistribute it and/or modify it under\n# the terms of the GNU General Public License as published by the Free Software\n# Foundation; either version 2 of the License, or (at your option) any later version.\n# \n# This program is distributed in the hope that it will be useful, but WITHOUT \n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin\n# Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nimport sys\nimport struct\nimport serial\nimport math\nimport time\nimport argparse\nimport os\nimport subprocess\n\nclass ESPROM:\n\n    # These are the currently known commands supported by the ROM\n    ESP_FLASH_BEGIN = 0x02\n    ESP_FLASH_DATA  = 0x03\n    ESP_FLASH_END   = 0x04\n    ESP_MEM_BEGIN   = 0x05\n    ESP_MEM_END     = 0x06\n    ESP_MEM_DATA    = 0x07\n    ESP_SYNC        = 0x08\n    ESP_WRITE_REG   = 0x09\n    ESP_READ_REG    = 0x0a\n\n    # Maximum block sized for RAM and Flash writes, respectively.\n    ESP_RAM_BLOCK   = 0x1800\n    ESP_FLASH_BLOCK = 0x100\n\n    # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want.\n    ESP_ROM_BAUD    = 230400\n    #ESP_ROM_BAUD     = 921600\n    #ESP_ROM_BAUD = 460800\n\n    # First byte of the application image\n    ESP_IMAGE_MAGIC = 0xe9\n\n    # Initial state for the checksum routine\n    ESP_CHECKSUM_MAGIC = 0xef\n\n    # OTP ROM addresses\n    ESP_OTP_MAC0    = 0x3ff00050\n    ESP_OTP_MAC1    = 0x3ff00054\n\n    def __init__(self, port = 0, baud = ESP_ROM_BAUD):\n        self._port = serial.Serial(port, 9600)\n        self._port = serial.Serial(port, baud)\n\n    \"\"\" Read bytes from the serial port while performing SLIP unescaping \"\"\"\n    def read(self, length = 1):\n        b = ''\n        while len(b) < length:\n            c = self._port.read(1)\n            if c == '\\xdb':\n                c = self._port.read(1)\n                if c == '\\xdc':\n                    b = b + '\\xc0'\n                elif c == '\\xdd':\n                    b = b + '\\xdb'\n                else:\n                    raise Exception('Invalid SLIP escape')\n            else:\n                b = b + c\n        return b\n\n    \"\"\" Write bytes to the serial port while performing SLIP escaping \"\"\"\n    def write(self, packet):\n        buf = '\\xc0'\n        for b in packet:\n            if b == '\\xc0':\n                buf += '\\xdb\\xdc'\n            elif b == '\\xdb':\n                buf += '\\xdb\\xdd'\n            else:\n                buf += b\n        buf += '\\xc0'\n        self._port.write(buf)\n\n    \"\"\" Calculate checksum of a blob, as it is defined by the ROM \"\"\"\n    @staticmethod\n    def checksum(data, state = ESP_CHECKSUM_MAGIC):\n        for b in data:\n            state ^= ord(b)\n        return state\n\n    \"\"\" Send a request and read the response \"\"\"\n    def command(self, op = None, data = None, chk = 0):\n        if op:\n            # Construct and send request\n            pkt = struct.pack('<BBHI', 0x00, op, len(data), chk) + data\n            self.write(pkt)\n\n        # Read header of response and parse\n        if self._port.read(1) != '\\xc0':\n            raise Exception('Invalid head of packet')\n        hdr = self.read(8)\n        (resp, op_ret, len_ret, val) = struct.unpack('<BBHI', hdr)\n        if resp != 0x01 or (op and op_ret != op):\n            raise Exception('Invalid response')\n\n        # The variable-length body\n        body = self.read(len_ret)\n\n        # Terminating byte\n        if self._port.read(1) != chr(0xc0):\n            raise Exception('Invalid end of packet')\n\n        return val, body\n\n    \"\"\" Perform a connection test \"\"\"\n    def sync(self):\n        self.command(ESPROM.ESP_SYNC, '\\x07\\x07\\x12\\x20'+32*'\\x55')\n        for i in xrange(7):\n            self.command()\n\n    \"\"\" Try connecting repeatedly until successful, or giving up \"\"\"\n    def connect(self):\n        print 'Connecting...'\n\n        # RTS = CH_PD (i.e reset)\n        # DTR = GPIO0\n        # self._port.setRTS(True)\n        # self._port.setDTR(False)        \n        # time.sleep(0.5)\n        # self._port.setRTS(False)        \n        # self._port.setDTR(True)\n\n\n        self._port.timeout = 0.5\n        for i in xrange(10):\n            try:\n                self._port.flushInput()\n                self._port.flushOutput()\n                self.sync()\n                self._port.timeout = 5\n                return\n            except:\n                time.sleep(0.1)\n        raise Exception('Failed to connect')\n\n    \"\"\" Read memory address in target \"\"\"\n    def read_reg(self, addr):\n        res = self.command(ESPROM.ESP_READ_REG, struct.pack('<I', addr))\n        if res[1] != \"\\0\\0\":\n            raise Exception('Failed to read target memory')\n        return res[0]\n\n    \"\"\" Write to memory address in target \"\"\"\n    def write_reg(self, addr, value, mask, delay_us = 0):\n        if self.command(ESPROM.ESP_WRITE_REG,\n                struct.pack('<IIII', addr, value, mask, delay_us))[1] != \"\\0\\0\":\n            raise Exception('Failed to write target memory')\n\n    \"\"\" Start downloading an application image to RAM \"\"\"\n    def mem_begin(self, size, blocks, blocksize, offset):\n        if self.command(ESPROM.ESP_MEM_BEGIN,\n                struct.pack('<IIII', size, blocks, blocksize, offset))[1] != \"\\0\\0\":\n            raise Exception('Failed to enter RAM download mode')\n\n    \"\"\" Send a block of an image to RAM \"\"\"\n    def mem_block(self, data, seq):\n        if self.command(ESPROM.ESP_MEM_DATA,\n                struct.pack('<IIII', len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != \"\\0\\0\":\n            raise Exception('Failed to write to target RAM')\n\n    \"\"\" Leave download mode and run the application \"\"\"\n    def mem_finish(self, entrypoint = 0):\n        if self.command(ESPROM.ESP_MEM_END,\n                struct.pack('<II', int(entrypoint == 0), entrypoint))[1] != \"\\0\\0\":\n            raise Exception('Failed to leave RAM download mode')\n\n    \"\"\" Start downloading to Flash (performs an erase) \"\"\"\n    def flash_begin(self, size, offset):\n        old_tmo = self._port.timeout\n        num_blocks = (size + ESPROM.ESP_FLASH_BLOCK - 1) / ESPROM.ESP_FLASH_BLOCK\n        self._port.timeout = 10\n        if self.command(ESPROM.ESP_FLASH_BEGIN,\n                struct.pack('<IIII', size, num_blocks, ESPROM.ESP_FLASH_BLOCK, offset))[1] != \"\\0\\0\":\n            raise Exception('Failed to enter Flash download mode')\n        self._port.timeout = old_tmo\n\n    \"\"\" Write block to flash \"\"\"\n    def flash_block(self, data, seq):\n        if self.command(ESPROM.ESP_FLASH_DATA,\n                struct.pack('<IIII', len(data), seq, 0, 0)+data, ESPROM.checksum(data))[1] != \"\\0\\0\":\n            raise Exception('Failed to write to target Flash')\n\n    \"\"\" Leave flash mode and run/reboot \"\"\"\n    def flash_finish(self, reboot = False):\n        pkt = struct.pack('<I', int(not reboot))\n        if self.command(ESPROM.ESP_FLASH_END, pkt)[1] != \"\\0\\0\":\n            raise Exception('Failed to leave Flash mode')\n\n    \"\"\" Run application code in flash \"\"\"\n    def run(self, reboot = False):\n        # Fake flash begin immediately followed by flash end\n        self.flash_begin(0, 0)\n        self.flash_finish(reboot)\n\n\nclass ESPFirmwareImage:\n    \n    def __init__(self, filename = None):\n        self.segments = []\n        self.entrypoint = 0\n\n        if filename is not None:\n            f = file(filename, 'rb')\n            (magic, segments, _, _, self.entrypoint) = struct.unpack('<BBBBI', f.read(8))\n            \n            # some sanity check\n            if magic != ESPROM.ESP_IMAGE_MAGIC or segments > 16:\n                raise Exception('Invalid firmware image')\n        \n            for i in xrange(segments):\n                (offset, size) = struct.unpack('<II', f.read(8))\n                if offset > 0x40200000 or offset < 0x3ffe0000 or size > 65536:\n                    raise Exception('Suspicious segment %x,%d' % (offset, size))\n                self.segments.append((offset, size, f.read(size)))\n\n            # Skip the padding. The checksum is stored in the last byte so that the\n            # file is a multiple of 16 bytes.\n            align = 15-(f.tell() % 16)\n            f.seek(align, 1)\n\n            self.checksum = ord(f.read(1))\n\n    def add_segment(self, addr, data):\n        # Data should be aligned on word boundary\n        l = len(data)\n        if l % 4:\n            data += b\"\\x00\" * (4 - l % 4)\n        self.segments.append((addr, len(data), data))\n\n    def save(self, filename):\n        f = file(filename, 'wb')\n        f.write(struct.pack('<BBBBI', ESPROM.ESP_IMAGE_MAGIC, len(self.segments), 0, 0, self.entrypoint))\n\n        checksum = ESPROM.ESP_CHECKSUM_MAGIC\n        for (offset, size, data) in self.segments:\n            f.write(struct.pack('<II', offset, size))\n            f.write(data)\n            checksum = ESPROM.checksum(data, checksum)\n\n        align = 15-(f.tell() % 16)\n        f.seek(align, 1)\n        f.write(struct.pack('B', checksum))\n\n\nclass ELFFile:\n\n    def __init__(self, name):\n        self.name = name\n        self.symbols = None\n\n    def _fetch_symbols(self):\n        if self.symbols is not None:\n            return\n        self.symbols = {}\n        try:\n            tool_nm = \"xtensa-lx106-elf-nm\"\n            if os.getenv('XTENSA_CORE')=='lx106':\n                tool_nm = \"xt-nm\"\n            proc = subprocess.Popen([tool_nm, self.name], stdout=subprocess.PIPE)\n        except OSError:\n            print \"Error calling \"+tool_nm+\", do you have Xtensa toolchain in PATH?\"\n            sys.exit(1)\n        for l in proc.stdout:\n            fields = l.strip().split()\n            self.symbols[fields[2]] = int(fields[0], 16)\n\n    def get_symbol_addr(self, sym):\n        self._fetch_symbols()\n        return self.symbols[sym]\n\n    def load_section(self, section):\n        tool_objcopy = \"xtensa-lx106-elf-objcopy\"\n        if os.getenv('XTENSA_CORE')=='lx106':\n            tool_objcopy = \"xt-objcopy\"\n        subprocess.check_call([tool_objcopy, \"--only-section\", section, \"-Obinary\", self.name, \".tmp.section\"])\n        f = open(\".tmp.section\", \"rb\")\n        data = f.read()\n        f.close()\n        os.remove(\".tmp.section\")\n        return data\n\n\ndef arg_auto_int(x):\n    return int(x, 0)\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser(description = 'ESP8266 ROM Bootloader Utility', prog = 'esptool')\n\n    parser.add_argument(\n            '--port', '-p',\n            help = 'Serial port device',\n            default = '/dev/ttyUSB0')\n\n    parser.add_argument(\n            '--baud', '-b',\n            help = 'Serial port baud rate',\n            type = arg_auto_int,\n            default = ESPROM.ESP_ROM_BAUD)\n\n    subparsers = parser.add_subparsers(\n            dest = 'operation',\n            help = 'Run esptool {command} -h for additional help')\n\n    parser_load_ram = subparsers.add_parser(\n            'load_ram',\n            help = 'Download an image to RAM and execute')\n    parser_load_ram.add_argument('filename', help = 'Firmware image')\n\n    parser_dump_mem = subparsers.add_parser(\n            'dump_mem',\n            help = 'Dump arbitrary memory to disk')\n    parser_dump_mem.add_argument('address', help = 'Base address', type = arg_auto_int)\n    parser_dump_mem.add_argument('size', help = 'Size of region to dump', type = arg_auto_int)\n    parser_dump_mem.add_argument('filename', help = 'Name of binary dump')\n\n    parser_read_mem = subparsers.add_parser(\n            'read_mem',\n            help = 'Read arbitrary memory location')\n    parser_read_mem.add_argument('address', help = 'Address to read', type = arg_auto_int)\n\n    parser_write_mem = subparsers.add_parser(\n            'write_mem',\n            help = 'Read-modify-write to arbitrary memory location')\n    parser_write_mem.add_argument('address', help = 'Address to write', type = arg_auto_int)\n    parser_write_mem.add_argument('value', help = 'Value', type = arg_auto_int)\n    parser_write_mem.add_argument('mask', help = 'Mask of bits to write', type = arg_auto_int)\n\n    parser_write_flash = subparsers.add_parser(\n            'write_flash',\n            help = 'Write a binary blob to flash')\n    parser_write_flash.add_argument('addr_filename', nargs = '+', help = 'Address and binary file to write there, separated by space')\n\n    parser_run = subparsers.add_parser(\n            'run',\n            help = 'Run application code in flash')\n\n    parser_image_info = subparsers.add_parser(\n            'image_info',\n            help = 'Dump headers from an application image')\n    parser_image_info.add_argument('filename', help = 'Image file to parse')\n\n    parser_make_image = subparsers.add_parser(\n            'make_image',\n            help = 'Create an application image from binary files')\n    parser_make_image.add_argument('output', help = 'Output image file')\n    parser_make_image.add_argument('--segfile', '-f', action = 'append', help = 'Segment input file') \n    parser_make_image.add_argument('--segaddr', '-a', action = 'append', help = 'Segment base address', type = arg_auto_int) \n    parser_make_image.add_argument('--entrypoint', '-e', help = 'Address of entry point', type = arg_auto_int, default = 0)\n\n    parser_elf2image = subparsers.add_parser(\n            'elf2image',\n            help = 'Create an application image from ELF file')\n    parser_elf2image.add_argument('input', help = 'Input ELF file')\n    parser_elf2image.add_argument('--output', '-o', help = 'Output filename prefix', type = str)\n\n    parser_read_mac = subparsers.add_parser(\n            'read_mac',\n            help = 'Read MAC address from OTP ROM')\n\n    args = parser.parse_args()\n\n    # Create the ESPROM connection object, if needed\n    esp = None\n    if args.operation not in ('image_info','make_image','elf2image'):\n        esp = ESPROM(args.port, args.baud)\n        esp.connect()\n\n    # Do the actual work. Should probably be split into separate functions.\n    if args.operation == 'load_ram':\n        image = ESPFirmwareImage(args.filename)\n\n        print 'RAM boot...'\n        for (offset, size, data) in image.segments:\n            print 'Downloading %d bytes at %08x...' % (size, offset),\n            sys.stdout.flush()\n            esp.mem_begin(size, math.ceil(size / float(esp.ESP_RAM_BLOCK)), esp.ESP_RAM_BLOCK, offset)\n\n            seq = 0\n            while len(data) > 0:\n                esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq)\n                data = data[esp.ESP_RAM_BLOCK:]\n                seq += 1\n            print 'done!'\n\n        print 'All segments done, executing at %08x' % image.entrypoint\n        esp.mem_finish(image.entrypoint)\n\n    elif args.operation == 'read_mem':\n        print '0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))\n\n    elif args.operation == 'write_mem':\n        esp.write_reg(args.address, args.value, args.mask, 0)\n        print 'Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)\n\n    elif args.operation == 'dump_mem':\n        f = file(args.filename, 'wb')\n        for i in xrange(args.size/4):\n            d = esp.read_reg(args.address+(i*4))\n            f.write(struct.pack('<I', d))\n            if f.tell() % 1024 == 0:\n                print '\\r%d bytes read... (%d %%)' % (f.tell(), f.tell()*100/args.size),\n                sys.stdout.flush()\n        print 'Done!'\n\n    elif args.operation == 'write_flash':\n        assert len(args.addr_filename) % 2 == 0\n        while args.addr_filename:\n            address = int(args.addr_filename[0], 0)\n            filename = args.addr_filename[1]\n            args.addr_filename = args.addr_filename[2:]\n            image = file(filename, 'rb').read()\n            print 'Erasing flash...'\n            blocks = math.ceil(len(image)/float(esp.ESP_FLASH_BLOCK))\n            esp.flash_begin(blocks*esp.ESP_FLASH_BLOCK, address)\n            seq = 0\n            while len(image) > 0:\n                print '\\rWriting at 0x%08x... (%d %%)' % (address + seq*esp.ESP_FLASH_BLOCK, 100*(seq+1)/blocks),\n                sys.stdout.flush()\n                block = image[0:esp.ESP_FLASH_BLOCK]\n                block = block + '\\xe0' * (esp.ESP_FLASH_BLOCK-len(block))\n                esp.flash_block(block, seq)\n                image = image[esp.ESP_FLASH_BLOCK:]\n                seq += 1\n            print\n        print '\\nLeaving...'\n        esp.flash_finish(False)\n\n    elif args.operation == 'run':\n        esp.run()\n\n    elif args.operation == 'image_info':\n        image = ESPFirmwareImage(args.filename)\n        print ('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set'\n        print '%d segments' % len(image.segments)\n        print\n        checksum = ESPROM.ESP_CHECKSUM_MAGIC\n        for (idx, (offset, size, data)) in enumerate(image.segments):\n            print 'Segment %d: %5d bytes at %08x' % (idx+1, size, offset)\n            checksum = ESPROM.checksum(data, checksum)\n        print\n        print 'Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!')\n\n    elif args.operation == 'make_image':\n        image = ESPFirmwareImage()\n        if len(args.segfile) == 0:\n            raise Exception('No segments specified')\n        if len(args.segfile) != len(args.segaddr):\n            raise Exception('Number of specified files does not match number of specified addresses')\n        for (seg, addr) in zip(args.segfile, args.segaddr):\n            data = file(seg, 'rb').read()\n            image.add_segment(addr, data)\n        image.entrypoint = args.entrypoint\n        image.save(args.output)\n\n    elif args.operation == 'elf2image':\n        if args.output is None:\n            args.output = args.input + '-'\n        e = ELFFile(args.input)\n        image = ESPFirmwareImage()\n        image.entrypoint = e.get_symbol_addr(\"call_user_start\")\n        for section, start in ((\".text\", \"_text_start\"), (\".data\", \"_data_start\"), (\".rodata\", \"_rodata_start\")):\n            data = e.load_section(section)\n            image.add_segment(e.get_symbol_addr(start), data)\n        image.save(args.output + \"0x00000.bin\")\n        data = e.load_section(\".irom0.text\")\n        off = e.get_symbol_addr(\"_irom0_text_start\") - 0x40200000\n        assert off >= 0\n        f = open(args.output + \"0x%05x.bin\" % off, \"wb\")\n        f.write(data)\n        f.close()\n\n    elif args.operation == 'read_mac':\n        mac0 = esp.read_reg(esp.ESP_OTP_MAC0)\n        mac1 = esp.read_reg(esp.ESP_OTP_MAC1)\n        print 'MAC: 18:fe:34:%02x:%02x:%02x' % ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff)\n"
  },
  {
    "path": "tools/makefile.sh",
    "content": "\n#\n# Generate the certificates and keys for encrypt.\n#\n\n# set default cert for use in the client\nxxd -i client.cer | sed -e \\\n        \"s/client_cer/default_certificate/\" > cert.h\n# set default key for use in the server\nxxd -i server.key_1024 | sed -e \\\n        \"s/server_key_1024/default_private_key/\" > private_key.h\n"
  },
  {
    "path": "tools/mkfs.py",
    "content": "#!/usr/bin/env python3\n#\n\nimport sys\nimport struct\nimport math\nimport time\nimport argparse\nimport os\nimport subprocess\nimport zlib\nimport gzip\n\nclass MKFS:\n\n\tdef __init__(self, src, dest):\n\t\tself._src = src\n\t\tself._dest = dest\t\t\n\t\tself._fileCount = 0\t\n\t\tself.data=bytearray()\n\t\tself.offset=0\n\n\tdef output_writeln(self,line):\n\t\tself.file_dest.write(line+'\\r\\n')\n\n\tdef writeFile(self,path,filename,compress):\n\t\twith open(path, \"rb\") as f:\n\t\t\t\n\t\t\t\n\t\t\tfileBytes = f.read()\n\t\t\t\n\n\t\t\tif compress:\n\t\t\t\tgzip_compress = zlib.compressobj(9, zlib.DEFLATED, zlib.MAX_WBITS | 16)\n\t\t\t\tgzip_data = gzip_compress.compress(fileBytes) + gzip_compress.flush()\n\t\t\t\tfileBytes = gzip_data\n\n\t\t\t\n\t\t\tfileLen = len(fileBytes)\t\t\t\n\t\t\tfileBytes = bytearray(fileBytes)\n\t\t\t\t\t\n\n\t\t\tself.output_writeln('\\t\\t{')\n\t\t\tself.output_writeln('\\t\\t.size='+str(fileLen)+',')\n\t\t\tself.output_writeln('\\t\\t.name = \"'+filename+'\",')\n\t\t\tif compress:\n\t\t\t\tself.output_writeln('\\t\\t.gzip=1,')\t\n\t\t\telse:\n\t\t\t\tself.output_writeln('\\t\\t.gzip=0,')\t\t\t\n\n\t\t\tself.output_writeln('\\t\\t.offset='+str(self.offset))\t\t\t\n\t\t\t\n\t\t\t#append data\n\t\t\tfor b in fileBytes:\n\t\t\t\tself.data.append(b)\n\t\t\t\n\n\t\t\tif self._innerCount == self._fileCount-1:\n\t\t\t\tself.output_writeln('\\t\\t}')\t\n\t\t\telse:\n\t\t\t\tself.output_writeln('\\t\\t},')\t\n\n\t\t\tself._innerCount+=1\n\t\t\tself.offset+=fileLen;\n\n\t\t\t#align\n\t\t\trest = 4-(self.offset)%4;\n\t\t\twhile rest > 0:\n\t\t\t\tself.offset=self.offset+1\n\t\t\t\tself.data.append(0);\n\t\t\t\trest=rest-1\n\n\n\t\t\t\t\t\n\tdef count(self):\n\t\tfor dirname, dirnames, filenames in os.walk(self._src):\n\t\t\t\n\t\t\t# print path to all filenames.\n\t\t\tfor filename in filenames:\n\t\t\t\tself._fileCount+=1\n\n\t\t\tif '.bak' in dirnames:\n\t\t\t\tdirnames.remove('.bak')\n\n\t\t\tif '.git' in dirnames:\n\t\t\t\t# don't go into any .git directories.\n\t\t\t\tdirnames.remove('.git')\n\n\tdef run(self):\n\t\tself.file_dest = open(self._dest,'w')\n\n\t\tself.count()\n\n\t\tself.output_writeln('//Generated by MKFS tool')\n\t\tself.output_writeln('//')\n\t\tself.output_writeln('#include \"rofs.h\"')\n\t\tself.output_writeln('#include \"c_types.h\"')\n\n\t\tself.output_writeln('#define ROFS_FILE_COUNT '+str(self._fileCount))\n\t\tself.output_writeln('const RO_FS ro_file_system = {')\n\t\tself.output_writeln('\\t.count='+str(self._fileCount)+',')\n\t\tself.output_writeln('\\t.files={')\t\t\n\n\t\tself._innerCount=0;\n\t\t#make full path\n\t\tfor dirname, dirnames, filenames in os.walk(self._src):\t\t\n\n\n\t\t\t# print path to all filenames.\n\t\t\tfor filename in filenames:\n\t\t\t\tself.writeFile(os.path.join(dirname,filename),filename,1)\n\n\t\t\t# Advanced usage:\n\t\t\t# editing the 'dirnames' list will stop os.walk() from recursing into there.\n\t\t\tif '.git' in dirnames:\n\t\t\t\t# don't go into any .git directories.\n\t\t\t\tdirnames.remove('.git')\n\n\t\t\tif '.bak' in dirnames:\n\t\t\t\tdirnames.remove('.bak')\n\n\t\tself.output_writeln('\\t}')\n\t\tself.output_writeln('};')\n\n\t\tfileHex = ', '.join(hex(x) for x in self.data)\t\n\n\n\t\tself.output_writeln('const ICACHE_STORE_ATTR ICACHE_RODATA_ATTR uint8_t rofs_data[]={'+fileHex+'};')\n\t\t#self.output_writeln('static ROFS_FILE_ENTRY ro_file_system_entries[]={'+','.join('file'+str(x) for x in range(0,self._fileCount-1))+'};')\n\t\t\n\nif __name__ == '__main__':\n\tparser = argparse.ArgumentParser(description = 'ROM FS make from dir', prog = 'mkfs')\n\n\tparser.add_argument(\n\t        '--src', '-s',\t        \n\t        help = 'Source directory')\n\n\tparser.add_argument(\n\t       '--dest', '-d',\t       \n\t       help = 'Destination file')\n\n\tparser.add_argument(\n\t       '--gzip', '-z',\t       \n\t       help = 'Destination file',\n\t       default=1)\n\n\targs = parser.parse_args()\n\t\n\tmkfs = MKFS(args.src,args.dest)\n\tmkfs.run()\n\n"
  }
]